Compare commits

..

561 Commits

Author SHA1 Message Date
github-actions[bot]
a851ef61bb Release preparation for version 2.7.5 2021-12-11 13:20:22 +00:00
Andrew Eisenberg
66c1629974 Merge pull request #7285 from github/post-release-prep-2.7.3-ddd4ccbb
Post-release preparation 2.7.3
2021-12-10 09:59:45 -08:00
yoff
d8857c7ce8 Merge pull request #7246 from tausbn/python/import-star-flow
Python: Support flow through `import *`
2021-12-10 16:34:32 +01:00
Henry Mercer
a46787ea07 Merge pull request #7351 from github/henrymercer/js-atm-heuristic-sinks-improvements
JS: Improve handling of heuristic sinks in endpoint filters
2021-12-10 14:56:45 +00:00
Rasmus Wriedt Larsen
bd9b96e154 Merge pull request #7331 from tausbn/python-fix-bad-callsite-points-to-join
Python: Fix bad `callsite_points_to` join
2021-12-10 15:39:49 +01:00
Rasmus Wriedt Larsen
8ee020f79c Merge pull request #7332 from tausbn/python-fix-bad-scope-entry-points-to-join
Python: Fix bad `scope_entry_points_to` join
2021-12-10 15:33:13 +01:00
Henry Mercer
6e167040f5 Merge pull request #7307 from adityasharad/atm/perf-debugging
JS/ATM: Various compilation fixes and performance improvements
2021-12-10 11:00:27 +00:00
Tom Hvitved
657cd89286 Merge pull request #7347 from hvitved/cfg/more-consistency-tests
Shared CFG: Add two more consistency queries
2021-12-10 10:50:39 +01:00
Arthur Baars
13f7fd88f1 Merge pull request #7283 from aibaars/ruby-pattern-matching-cfg
Ruby: pattern matching: CFG
2021-12-10 10:24:38 +01:00
Anders Schack-Mulligen
634ed91904 Merge pull request #7346 from github/workflow/coverage/update
Update CSV framework coverage reports
2021-12-10 10:12:23 +01:00
Tom Hvitved
cf42427f54 Merge pull request #7321 from hvitved/csharp/cil/unique-type
C#: Avoid CIL instructions with multiple types
2021-12-10 09:58:06 +01:00
Tom Hvitved
f7f3890b40 Merge pull request #7320 from hvitved/csharp/unknown-type
C#: Populate `UnknownType`
2021-12-10 09:57:55 +01:00
Tom Hvitved
70f76d06c7 Shared CFG: Add two more consistency queries 2021-12-10 09:56:50 +01:00
Tom Hvitved
45c0d4a3b2 Merge pull request #7343 from hvitved/cfg/consistency-test
Shared CFG: Add another consistency test
2021-12-10 09:49:05 +01:00
github-actions[bot]
7e5bfa5aa0 Add changed framework coverage reports 2021-12-10 00:09:34 +00:00
Aditya Sharad
271b23ba8f JS: Expand explanatory comment about version placeholders 2021-12-09 13:43:08 -08:00
Aditya Sharad
0c3daabc51 JS: Fix broken regex matching predicate
The receiver string and the regex were in the wrong order,
leading to test failures when looking for matching comments.
2021-12-09 13:42:33 -08:00
Chris Smowton
753d886b0d Merge pull request #6319 from haby0/java/MyBatisSqlInjection
[Java] CWE-089 MyBatis Mapper Sql Injection
2021-12-09 19:57:18 +00:00
Taus
6d247bfdf9 Merge pull request #7330 from tausbn/python-fix-bad-adjacentuseuse-join
Python: Fix bad join in SSA
2021-12-09 20:55:45 +01:00
Erik Krogh Kristensen
e7209d1ee1 Merge pull request #7216 from erik-krogh/ts45
JS: Add support for TypeScript 4.5
2021-12-09 20:33:52 +01:00
Chris Smowton
75f3ebf051 Fix OTHER XML tag 2021-12-09 17:55:03 +00:00
Chris Smowton
9f69c75c50 Fix XML tag 2021-12-09 17:44:49 +00:00
Chris Smowton
2cd70b96cd Fix doctype 2021-12-09 17:44:08 +00:00
Michael Nebel
df482a9603 Merge pull request #7314 from michaelnebel/csharp-stubs-dataflow-global
C#: Update tests dataflow/global tests to use stubs.
2021-12-09 16:31:39 +01:00
Chris Smowton
470256da85 Copyedit 2021-12-09 15:10:07 +00:00
Tony Torralba
8bba3eb2b6 Merge pull request #6823 from atorralba/atorralba/android-notification-models
Android: Add models for `android.app.Notification` builders
2021-12-09 16:01:44 +01:00
Henry Mercer
f08f07e19e JS: Improve handling of heuristic sinks in endpoint filters
Previously heuristic sinks were always included, to avoid us filtering
them out due to not being an argument to an external library call.
In this commit we move the argument to an external library call
filtering to the query-specific endpoint filters.
This lets us filter out heuristic sinks if they match one of the other
endpoint filters, reducing FPs.
2021-12-09 15:00:54 +00:00
Chris Smowton
d0a19fffee Copyedit 2021-12-09 14:58:29 +00:00
Tom Hvitved
7e99426141 C#: Address review comments 2021-12-09 15:51:54 +01:00
Tom Hvitved
2bf5966fe3 C#: Address review comment 2021-12-09 15:44:43 +01:00
Arthur Baars
fd4915a564 Ruby: CFG: add default implementation for getAnInnerCompatibleCompletion 2021-12-09 15:23:26 +01:00
Arthur Baars
9d288c90a5 Ruby: CFG: better return type for getAMatchingSuccessorType 2021-12-09 15:23:26 +01:00
Arthur Baars
a7b3f1370f Ruby: CFG: add test case 2021-12-09 15:23:26 +01:00
Arthur Baars
d0aa307bd3 Ruby: CFG: fix multiple successors failure for default parameters 2021-12-09 15:23:26 +01:00
Tom Hvitved
b887165005 Ruby: Code review suggestions 2021-12-09 15:23:26 +01:00
Arthur Baars
3689481c18 Ruby: CFG: make Completion.isValidFor work for getSugared AST nodes 2021-12-09 15:23:26 +01:00
Arthur Baars
660e52f2bf Ruby: CFG: make VariableReferencePattern a PreOrder node 2021-12-09 15:23:26 +01:00
Arthur Baars
e9e3ef3ea2 Ruby: 'self' is not really a local variable 2021-12-09 15:23:26 +01:00
Arthur Baars
799c945299 Ruby: fix CFG for AsPattern 2021-12-09 15:23:26 +01:00
Arthur Baars
95f8f85aa2 Ruby: fix allowed completions for desugared CasePatterns 2021-12-09 15:23:26 +01:00
Arthur Baars
aacba0b522 Ruby: CFG: add test cases for pattern matching 2021-12-09 15:23:26 +01:00
Arthur Baars
513fe09dbb Treat class names in array/find/hash patterns as sub-patterns 2021-12-09 15:23:26 +01:00
Arthur Baars
d17c055139 CFG 2021-12-09 15:23:25 +01:00
Arthur Baars
44a615839d Add test case with rest variable and no prefix elements 2021-12-09 15:23:25 +01:00
Arthur Baars
f08eb8e616 Revert "Temporarily allow CFG inconsistencies"
This reverts commit dca1e34cd8.
2021-12-09 15:23:25 +01:00
Michael Nebel
69f42b9c74 C#: Update remaining tests. 2021-12-09 15:21:08 +01:00
Tony Torralba
38250b0821 Remove unnecessary implicit read step 2021-12-09 15:18:38 +01:00
Tom Hvitved
cbc96dba8a Shared CFG: Add another consistency test
Finds nodes with multiple normal successors, where one is the special simple
successor. For example, this would flag a node that has both a "simple" and
a "true" successor.
2021-12-09 15:08:19 +01:00
Tony Torralba
522a4bb9fa Propagate extras through build methods 2021-12-09 14:56:52 +01:00
yoff
8e11c2c476 Merge pull request #7259 from RasmusWL/even-more-path-injection-sinks
Python: Add more path-injection sinks from `os` and `tempfile` modules
2021-12-09 14:46:41 +01:00
Michael Nebel
992801b7cb C#: Update GetAnOutNode test. 2021-12-09 13:55:04 +01:00
Tom Hvitved
9ffa236c51 Merge pull request #7288 from hvitved/cfg/enclosing-scope
Shared CFG: Include CFG scope in `TElementNode`
2021-12-09 13:39:48 +01:00
Tony Torralba
c0c40cc05b Remove synthetic fields 2021-12-09 13:34:41 +01:00
Tony Torralba
3a3c7fc59e Fix stub 2021-12-09 13:34:41 +01:00
Tony Torralba
f209ff4f76 Use synthetic fields to improve taint precision 2021-12-09 13:34:39 +01:00
Tony Torralba
b7f7c5ba20 Change format of fluent models to make review easier 2021-12-09 13:33:19 +01:00
Tony Torralba
f63ffb0630 Add models for Notification builders 2021-12-09 13:33:17 +01:00
Tom Hvitved
069cf9d17f C#: Exclude stubs in GetAnOutNode.ql test 2021-12-09 13:33:14 +01:00
Tom Hvitved
cbd21edc99 C#: Override File::isFromSource in tests to exclude stubs 2021-12-09 13:33:14 +01:00
Michael Nebel
2f85735b6a C#: Use stubs instead of dll's in the dataflow global tests. 2021-12-09 13:25:11 +01:00
Tom Hvitved
69ba2e6f8c Merge pull request #7337 from michaelnebel/csharp-synthetic-field
C#: Introduce synthetic fields and use them in Task<>.
2021-12-09 13:18:44 +01:00
Taus
b871342e83 Python: A small further performance improvement
Unrolling the transitive closure had slightly better performance here.

Also, we exclude names of builtins, since those will be handled by a
separate case of `isDefinedLocally`.
2021-12-09 10:29:55 +00:00
Michael Nebel
13347cd102 C#: Add Ql docs to synthetic fields. 2021-12-09 10:34:31 +01:00
Michael Nebel
9f4b965202 C#: Update the flow summaries produced for Task<> after introduction of synthetic fields. 2021-12-09 10:11:49 +01:00
Michael Nebel
d70d1fbf81 C#: Add support for the use of synthetic fields in flow summary CSV. 2021-12-09 10:11:48 +01:00
Michael Nebel
a43704ab43 C#: Update dataflow/global tests based on synthetic fields. 2021-12-09 10:11:48 +01:00
Michael Nebel
063398f24d C#: Use synthetic fields for Task instead of referring to private fields. 2021-12-09 10:11:48 +01:00
Michael Nebel
60f3ff8c33 C#: Introduce type for Synthetic fields. 2021-12-09 10:11:48 +01:00
haby0
8bcbf8e30f rename isMybatisCollectionTypeSqlInjection 2021-12-09 09:16:33 +08:00
Taus
8517eff0f7 Python: Fix bad performance
A few changes, all bundled together:

- We were getting a lot of magic applied to the predicates in the
  `ImportStar` module, and this was causing needless re-evaluation.
  To address this, the easiest solution was to simply cache the entire
  module.
- In order to separate this from the dataflow analysis and make it
  dependent only on control flow, `potentialImportStarBase` was changed
  to return a `ControlFlowNode`.
- `isDefinedLocally` was defined on control flow nodes, which meant we
  were duplicating a lot of tuples due to control flow splitting, to no
  actual benefit.

Finally, there was a really bad join in `isDefinedLocally` that was
fixed by separating out a helper predicate. This is a case where we
could use a three-way join, since the join between the `Scope`, the
`name` string and the `Name` is big no matter what.

If we join `scope_defines_name` with `n.getId()`, we'll get `Name`s
belonging to irrelevant scopes.

If we join `scope_defines_name` with the enclosing scope of the `Name`
`n`, then we'll get this also for `Name`s that don't share their `getId`
with the local variable defined in the scope.

If we join `n.getId()` with `n.getScope()...` then we'll get all
enclosing scopes for each `Name`.

The last of these is what we currently have. It's not terrible, but not
great either. (Though thankfully it's rare to have lots of enclosing
scopes.)
2021-12-08 22:53:45 +00:00
Tom Hvitved
b49ca6a24c Merge pull request #7335 from hvitved/ruby/dataflow/hide-desugared-nodes
Ruby: Hide desugared nodes in data-flow paths
2021-12-08 17:39:48 +01:00
haby0
a18aad8536 Fix one 2021-12-08 21:03:17 +08:00
Anders Schack-Mulligen
38d0bb4a60 Merge pull request #7260 from hvitved/dataflow/argument-parameter-matching
Data flow: Introduce `ParameterPosition` and `ArgumentPosition`
2021-12-08 12:49:08 +01:00
haby0
1d321c692b Refactor isMybatisXmlOrAnnotationSqlInjection 2021-12-08 18:59:55 +08:00
Alex Ford
ede1503cc6 Merge pull request #7328 from github/ruby/customizations
Ruby: add `Customizations.qll` file
2021-12-08 10:54:23 +00:00
Tom Hvitved
283173ad02 Address review comments 2021-12-08 11:26:44 +01:00
Erik Krogh Kristensen
3145e8f9b7 add upgrade script 2021-12-08 10:53:47 +01:00
Erik Krogh Kristensen
1956405d17 Merge pull request #7284 from erik-krogh/myApply-part1
JS: remove paths without unmatched returns from polynomial-redos
2021-12-08 10:46:03 +01:00
Tom Hvitved
5735bb698d Ruby: Hide desugared nodes in data-flow paths 2021-12-08 09:00:16 +01:00
yoff
0e33f730b1 Merge pull request #7329 from tausbn/tausbn/python-fix-syntax-error-locations
Python: Fix syntax error locations
2021-12-07 22:45:35 +01:00
Alex Ford
ea7063f3c6 Ruby: make Customizations import private 2021-12-07 19:43:08 +00:00
Tom Hvitved
490872173a Data flow: Sync files 2021-12-07 20:29:18 +01:00
Tom Hvitved
07ca1c2ec0 Data flow: Adjust parameterMatch join-orders 2021-12-07 20:29:00 +01:00
Taus
e7c298d903 Python: Fix bad scope_entry_points_to join
From `pritomrajkhowa/LoopBound`:

```
Definitions.ql-7:PointsTo::PointsToInternal::scope_entry_points_to#ffff#antijoin_rhs#2 ........... 55.1s
```

specifically

```
(443s) Tuple counts for PointsTo::PointsToInternal::scope_entry_points_to#ffff#antijoin_rhs#2/3@74a7cart after 55.1s:
184070    ~0%        {3} r1 = JOIN PointsTo::PointsToInternal::scope_entry_points_to#ffff#shared#1 WITH Variables::GlobalVariable#class#f ON FIRST 1 OUTPUT Lhs.0 'arg2', Lhs.1 'arg0', Lhs.2 'arg1'
184070    ~0%        {3} r2 = STREAM DEDUP r1
919966523 ~2%        {4} r3 = JOIN r2 WITH Essa::EssaDefinition::getSourceVariable_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'arg0', Lhs.2 'arg1', Lhs.0 'arg2'
4281779   ~2293%     {3} r4 = JOIN r3 WITH Essa::EssaVariable::getScope_dispred#ff ON FIRST 2 OUTPUT Lhs.1 'arg0', Lhs.2 'arg1', Lhs.3 'arg2'
                    return r4
```

First, this is an `antijoin`, so there's likely some negation involved.
Also, there's mention of `GlobalVariable`, `getScope`, and
`getSourceVariable`, none of which appear in `scope_entry_points_to`, so
it's likely that something got inlined.

Taking a closer look at the predicates mentioned in the body, we spot
`undefined_variable` as a likely culprit.

Evaluating this predicate in isolation reveals that it's not terribly
big, so we could try just marking it with `pragma[noinline]` (I opted
for the slightly more solid `nomagic`) and see how that fares. I also
checked that `builtin_not_in_outer_scope` was similarly small, and
made that one un-inlineable as well.

The result? Well, I can't even show you. Both `scope_entry_points_to`
and `undefined_variable` are so fast that they don't appear in the
clause timing report (so they can at most take 3.5s each to evaluate, as
that is the smallest timing in the list).
2021-12-07 18:51:44 +00:00
Taus
b502ca1ea7 Python: Fix bad callsite_points_to join
From `pritomrajkhowa/LoopBound`:

```
Definitions.ql-7:PointsTo::InterProceduralPointsTo::callsite_points_to#ffff#join_rhs#3 ........... 5m53s
```

specifically

```
(767s) Tuple counts for PointsTo::InterProceduralPointsTo::callsite_points_to#ffff#join_rhs#3/3@f8f86764 after 5m53s:
832806293 ~0%     {4} r1 = JOIN PointsTo::InterProceduralPointsTo::callsite_points_to#ffff#shared#1 WITH PointsTo::InterProceduralPointsTo::var_at_exit#fff ON FIRST 1 OUTPUT Lhs.0, Lhs.1 'arg1', Rhs.1 'arg2', Rhs.2 'arg0'
832806293 ~0%     {3} r2 = JOIN r1 WITH Essa::TEssaNodeRefinement#ffff_03#join_rhs ON FIRST 2 OUTPUT Lhs.3 'arg0', Lhs.1 'arg1', Lhs.2 'arg2'
                return r2
```

This one is a bit tricky to unpack. Where is this `shared#1` defined?

```
EVALUATE NONRECURSIVE RELATION:
SYNTHETIC PointsTo::InterProceduralPointsTo::callsite_points_to#ffff#shared#1(int arg0, numbered_tuple arg1) :-
    SENTINEL PointsTo::InterProceduralPointsTo::callsite_points_to#ffff#shared
    SENTINEL Definitions::EscapingAssignmentGlobalVariable#class#f
    SENTINEL Essa::TEssaNodeRefinement#ffff_03#join_rhs
    {2} r1 = JOIN PointsTo::InterProceduralPointsTo::callsite_points_to#ffff#shared WITH Definitions::EscapingAssignmentGlobalVariable#class#f ON FIRST 1 OUTPUT Lhs.0 'arg0', Lhs.1 'arg1'
    {2} r2 = STREAM DEDUP r1
    {2} r3 = JOIN r2 WITH Essa::TEssaNodeRefinement#ffff_03#join_rhs ON FIRST 2 OUTPUT Lhs.0 'arg0', Lhs.1 'arg1'
    {2} r4 = STREAM DEDUP r3
    return r4
```

Looking at `callsite_points_to`, we see a likely candidate in `srcvar`.
It is guarded with an `instanceof` check for
`EscapingAssignmentGlobalVariable` (which lines up nicely with the
sentinel on its charpred) and `getSourceVariable` is just a projection
of `TEssaNodeRefinement`.

So let's try unbinding `srcvar` to prevent an early join.

The timing is now:

```
Definitions.ql-7:PointsTo::InterProceduralPointsTo::callsite_points_to#ffff ...................... 31.3s (2554 evaluations with max 101ms in PointsTo::InterProceduralPointsTo::callsite_points_to#ffff/4@i516#581fap5w)
```
(Showing the tuple counts doesn't make sense here, since all of the
`shared` and `join_rhs` predicates have been smooshed around.)
2021-12-07 18:25:53 +00:00
Taus
a716482c1f Python: Fix bad join in SSA
On `pritomrajkhowa/LoopBound`:

```
Definitions.ql-3:SsaCompute::SsaComputeImpl::AdjacentUsesImpl::adjacentUseUse#ff ................. 4m35s
```

specifically

```
(376s) Tuple counts for SsaCompute::SsaComputeImpl::AdjacentUsesImpl::adjacentUseUse#ff/2@be04e9kp after 4m58s:
388843     ~0%     {4} r1 = JOIN Essa::TPhiFunction#fff_2#join_rhs WITH SsaCompute::SsaComputeImpl::AdjacentUsesImpl::definesAt#ffff ON FIRST 1 OUTPUT Rhs.1, Lhs.0, Rhs.2, Rhs.3
3629812090 ~1%     {7} r2 = JOIN r1 WITH SsaCompute::SsaComputeImpl::variableUse#ffff ON FIRST 1 OUTPUT Lhs.0, Rhs.2, Rhs.3, Lhs.2, Lhs.3, Lhs.1, Rhs.1 'use1'
0          ~0%     {2} r3 = JOIN r2 WITH SsaCompute::SsaComputeImpl::AdjacentUsesImpl::adjacentVarRefs#fffff ON FIRST 5 OUTPUT Lhs.5, Lhs.6 'use1'
0          ~0%     {2} r4 = JOIN r3 WITH SsaCompute::SsaComputeImpl::AdjacentUsesImpl::firstUse#ff ON FIRST 1 OUTPUT Lhs.1 'use1', Rhs.1 'use2'

897141     ~0%     {2} r5 = SsaCompute::SsaComputeImpl::AdjacentUsesImpl::adjacentUseUseSameVar#ff UNION r4
                    return r5
```

Clearly we do not want to join on the variable so soon. So we unbind it
and get

```
(78s) Tuple counts for SsaCompute::SsaComputeImpl::AdjacentUsesImpl::adjacentUseUse#ff/2@40e0e6uv after 434ms:
3377959 ~2%     {4} r1 = SCAN SsaCompute::SsaComputeImpl::variableUse#ffff OUTPUT In.0, In.2, In.3, In.1 'use1'
1026855 ~2%     {4} r2 = JOIN r1 WITH SsaCompute::SsaComputeImpl::AdjacentUsesImpl::adjacentVarRefs#fffff ON FIRST 3 OUTPUT Lhs.0, Rhs.3, Rhs.4, Lhs.3 'use1'
129484  ~0%     {2} r3 = JOIN r2 WITH SsaCompute::SsaComputeImpl::AdjacentUsesImpl::definesAt#ffff_1230#join_rhs ON FIRST 3 OUTPUT Rhs.3, Lhs.3 'use1'
0       ~0%     {2} r4 = JOIN r3 WITH Essa::TPhiFunction#fff_2#join_rhs ON FIRST 1 OUTPUT Lhs.0, Lhs.1 'use1'
0       ~0%     {2} r5 = JOIN r4 WITH SsaCompute::SsaComputeImpl::AdjacentUsesImpl::firstUse#ff ON FIRST 1 OUTPUT Lhs.1 'use1', Rhs.1 'use2'

897141  ~0%     {2} r6 = SsaCompute::SsaComputeImpl::AdjacentUsesImpl::adjacentUseUseSameVar#ff UNION r5
                return r6
```
2021-12-07 18:19:47 +00:00
Taus
59bac04d8f Python: Fix Python 2 failures 2021-12-07 18:00:46 +00:00
Taus
ffc858e34d Python: Add missing file 2021-12-07 17:29:35 +00:00
Alex Ford
bf0ecded04 Merge pull request #7326 from github/ginsbach/FixInstanceof
fix dependency cycle by removing superfluous classes
2021-12-07 17:05:26 +00:00
Taus
7437cd4d85 Python: Fix syntax error locations 2021-12-07 16:51:33 +00:00
Alex Ford
f85a47d41f Ruby: add Customizations.qll file 2021-12-07 15:37:04 +00:00
Tom Hvitved
a2dc505c26 Merge pull request #7317 from hvitved/ruby/param-node-refactor
Ruby: Restructure `ParameterNode(Impl)`
2021-12-07 16:29:49 +01:00
Tom Hvitved
5183290439 Merge pull request #7315 from hvitved/ruby/inline-flow-test
Ruby: Add `InlineFlowTest.qll`
2021-12-07 16:29:34 +01:00
Henry Mercer
322e39446d JS: Autoformat 2021-12-07 14:17:11 +00:00
Henry Mercer
016727d6b6 JS: Fix occasional duplicate body tokens
0e31439 introduces some occasional duplicate tokens due to duplicate AST
node attributes. The long-term fix is to update `CodeToFeatures.qll`,
but for the short-term, we update the concatenation to concatenate
unique (location, token) pairs.
2021-12-07 14:16:48 +00:00
Philip Ginsbach
b2c1b55c0c rephrase extensions as aliases 2021-12-07 13:09:25 +00:00
Tom Hvitved
b17a93eaad Merge pull request #7316 from hvitved/ruby/is-private-join
Ruby: Tweak `Method::isPrivate` join-orders
2021-12-07 13:58:19 +01:00
Tom Hvitved
4d797d6b3d Merge pull request #7324 from github/hmac/empty-else-cfg
Ruby: Include empty StmtSequences in CFG
2021-12-07 13:19:15 +01:00
Philip Ginsbach
da43984ba4 fix dependency cycle by removing superfluous classes 2021-12-07 11:59:04 +00:00
Rasmus Wriedt Larsen
ee23799a59 Merge pull request #7319 from RasmusWL/js-cwe-328
JS: Tag queries with CWE-328
2021-12-07 11:40:33 +01:00
Anders Schack-Mulligen
6c739b67fa Merge pull request #7318 from RasmusWL/java-cwe-328
Java: Tag queries with CWE-328
2021-12-07 11:39:48 +01:00
Erik Krogh Kristensen
3c59aa319e Merge pull request #7245 from erik-krogh/explicit-this-all-the-places
All langs: apply the explicit-this patch to all remaining code
2021-12-07 10:40:26 +01:00
Taus
7cd9369d91 Python: Autoformat 2021-12-07 09:29:24 +00:00
Taus
33a9f86f54 Python: Change integer in trois.py 2021-12-07 08:54:07 +00:00
Taus
dd33f4f4d2 Python: Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2021-12-07 09:48:53 +01:00
Harry Maclean
6f42153eac Ruby: Include empty StmtSequences in CFG
Empty StmtSequences appear, for example, in the `else` branch of `if`
statements like the following:

    foo

    if cond
      bar
    else
    end

    baz

Before this change, the CFG for this code would look like this:

        foo
         │
         │
         ▼
        cond
         │
    true │
         ▼
        bar
         │
         │
         ▼
         if
         │
         │
         ▼
        baz

i.e. there is linear flow through the condition, the `then` branch, and
out of the if. This doesn't account for the possibility that the
condition is false and `bar` is not executed. After this change, the CFG
looks like this:

          foo
           │
           │
           ▼
          cond
         │    │
    true │    │ false
         ▼    │
        bar   │
         │    │
         │    │
         ▼    ▼
           if
           │
           │
           ▼
          baz

i.e. we correctly account for the `false` condition.
2021-12-07 16:01:50 +13:00
Geoffrey White
4e68a4670b Merge pull request #7322 from MathiasVP/fix-performance-of-unused-static-functions
C++: Fix performance of 'cpp/unused-static-function'.
2021-12-06 17:30:51 +00:00
Mathias Vorreiter Pedersen
4765772725 C++: Fix performance of 'cpp/unused-static-function'. 2021-12-06 16:41:10 +00:00
Tom Hvitved
243b92b28c C#: Avoid CIL instructions with multiple types 2021-12-06 14:42:41 +01:00
Tom Hvitved
60c0bcf8f7 C#: Include dup instructions in CIL ExprMissingType consistency test 2021-12-06 14:37:07 +01:00
Tom Hvitved
c39fe59a04 C#: Populate UnknownType 2021-12-06 14:09:17 +01:00
Rasmus Wriedt Larsen
7ae1047fda JS: Tag queries with CWE-328
CWE-328: Use of Weak Hash, see https://cwe.mitre.org/data/definitions/328.html
2021-12-06 14:02:24 +01:00
Rasmus Wriedt Larsen
ff9ed0d4fb Java: Tag queries with CWE-328
CWE-328: Use of Weak Hash, see https://cwe.mitre.org/data/definitions/328.html

Since weak hash functions (md5/sha1) are considered for the
`java/weak-cryptographic-algorithm` query. See
caeeebf572/java/ql/lib/semmle/code/java/security/Encryption.qll (L148)

To keep things consistent between `java/weak-cryptographic-algorithm`
and `java/potentially-weak-cryptographic-algorithm`, I also added the
tag to the latter.
2021-12-06 13:59:00 +01:00
Tom Hvitved
5dbbb86d46 Ruby: Restructure ParameterNode(Impl) 2021-12-06 13:43:19 +01:00
Tom Hvitved
728e3abee5 Ruby: Tweak Method::isPrivate join-orders 2021-12-06 13:36:48 +01:00
Tom Hvitved
36569f997f Ruby: Add InlineFlowTest.qll 2021-12-06 13:35:07 +01:00
Mathias Vorreiter Pedersen
6b1ac73a46 Merge pull request #7177 from ihsinme/ihsinme-patch-6141
fix request for cpp exceptions
2021-12-06 09:24:59 +00:00
Anders Schack-Mulligen
de1269f18f Merge pull request #7308 from github/workflow/coverage/update
Update CSV framework coverage reports
2021-12-06 09:58:49 +01:00
github-actions[bot]
c46ede02e6 Add changed framework coverage reports 2021-12-06 00:09:47 +00:00
Alex Ford
6adfea2365 Merge pull request #7163 from github/ruby/file-reader-extend
Ruby: Extend `FileSystemReadAccess` to include more potential sources of input from the filesystem
2021-12-05 23:32:43 +00:00
haby0
daf6a4ce07 Partial modification 2 2021-12-04 17:45:02 +08:00
Aditya Sharad
f68a40f82b JS: Simplify calculation of token features for endpoints
Use a `strictcount` to identify whether there is exactly one feature or not.
If so, we use it. If not, we use the empty string.
Add context to ensure we filter the set of data flow nodes down to only
the set of endpoint nodes.

This performance optimisation avoids calculating the Cartesian product
of data flow nodes and feature names, but it does not avoid calculating
the (slightly smaller) Cartesian product of endpoint nodes and feature names.
Product size = number of endpoint nodes * number of feature names.
At time of writing there are 8 feature names.
2021-12-03 14:20:27 -08:00
Aditya Sharad
fac2769d85 JS: Replace an exists+concat with an equivalent strictconcat 2021-12-03 14:20:26 -08:00
Aditya Sharad
0e31439b7e JS: Simplify aggregation of tokens into entity strings
Change the cutoff logic from `count` to `strictcount`, since we know it only applies
to a non-empty set of results.

Use a single `strictconcat` aggregate to combine tokens in order of location,
instead of computing a `rank` followed by a `concat`.

Strictness introduces a slight change of behaviour because missing tokens will now result
in no results from the predicate rather than an empty feature string.
2021-12-03 14:20:26 -08:00
Aditya Sharad
2a3b5fc2b2 JS: Performance optimisation for matching framework libraries with their marker comments
The `matchMarkerComment` predicate performs badly on any codebase with
a moderately large number of comments, because the current implementation
has to first compute the Cartesian product between the set of comments
and the set of framework library comment regexes.

Instead, match first against a single regex:
the union of all framework library comment regexes.
This computes a more benign Cartesian product, the same size as the set of comments.

See inline comments for more details.
2021-12-03 14:20:26 -08:00
Aditya Sharad
d0840afb80 JS: Fix compilation errors in EndpointFeatures library
Use the LabelParameter API instead of manually constructing the edge label.
2021-12-03 14:20:17 -08:00
Arthur Baars
9f48ae656f Merge pull request #7306 from aibaars/ruby-parenthesized-pattern
Ruby: parenthesized patterns
2021-12-03 19:18:09 +01:00
Arthur Baars
0805daaa56 Update ruby/ql/lib/codeql/ruby/ast/Pattern.qll
Add missing backticks
2021-12-03 18:44:21 +01:00
Arthur Baars
51998294ad Ruby: add AST classes for parenthesized patterns 2021-12-03 18:13:53 +01:00
Tony Torralba
4ae99592a3 Merge pull request #6801 from atorralba/atorralba/android_slice_models
Android: Add `androidx.slice.builders` models
2021-12-03 17:44:09 +01:00
Arthur Baars
205233b42f Add trivial upgrade 2021-12-03 17:04:00 +01:00
Arthur Baars
3e1ebb954f Ruby: update generated dbscheme and library 2021-12-03 17:02:08 +01:00
Arthur Baars
0cec59e043 Ruby: update tree-sitter grammar 2021-12-03 17:01:12 +01:00
Tony Torralba
8ffa195538 Merge branch 'main' into atorralba/android_slice_models 2021-12-03 16:59:33 +01:00
Nick Rolfe
5a2ef8321c Merge pull request #7120 from github/nickrolfe/regexp_g_anchor
Ruby/Python: parse anchors in regexes as special characters
2021-12-03 15:24:38 +00:00
Michael Nebel
4128f56aa9 Merge pull request #7289 from michaelnebel/csharp-mad-as-csv
C#: Convert some of the existing flow summaries to CSV
2021-12-03 15:09:36 +01:00
haby0
6c6113b85b Partial modification 2021-12-03 18:59:24 +08:00
Arthur Baars
802faf1197 Merge pull request #7296 from intrigus-lgtm/patch-7
Fix QL Doc typo.
2021-12-03 11:54:22 +01:00
Michael Nebel
7ad52e1365 C#: Address review comments from hvitved. 2021-12-03 11:12:31 +01:00
Michael Nebel
f00b62df76 C#: Convert System.Uri flow to CSV format. 2021-12-03 11:10:24 +01:00
Michael Nebel
90baef83ee C#: Add flow summaries for another TryParse method in System.Boolean. 2021-12-03 11:10:24 +01:00
Michael Nebel
8eb041c172 C#: Convert System.Boolean flow to CSV format. 2021-12-03 11:10:24 +01:00
Tom Hvitved
520f598d49 Merge pull request #7301 from hvitved/ruby/cfg-disjunct-test
Ruby: Add CFG test for `||`
2021-12-03 09:57:40 +01:00
Tom Hvitved
d9704d7b39 Ruby: Adapt to shared CFG changes 2021-12-03 09:37:41 +01:00
Tom Hvitved
42f6dfc197 Sync files 2021-12-03 09:37:41 +01:00
Tom Hvitved
404f4a81a7 C#: Include CFG scope in TElementNode 2021-12-03 09:37:41 +01:00
Tom Hvitved
50dd4e7ee7 Ruby: Add CFG test for || 2021-12-03 09:16:11 +01:00
Arthur Baars
f2800abee4 Merge pull request #7299 from github/nickrolfe/clippy_fixes
Ruby: extractor: fix warnings from Clippy
2021-12-02 18:52:22 +01:00
Taus
7f44cebed7 Python: Add missing hidden flow
The easiest way to implement this was to change the definition of
`module_export` to account for chains of `import *`. We reuse the
machinery from `ImportStar.qll` for this, naturally.
2021-12-02 17:11:56 +00:00
Taus
4138296ec6 Python: Add test for "hidden" import * flow
TL;DR: We were missing out on flow in the following situation:

`mod1.py`:
```python
foo = SOURCE
```

`mod2.py`:
```python
from mod1 import *
```

`test.py`:
```python
from mod2 import foo
SINK(foo)
```

This is because there's no node at which a read of `foo` takes place
within `test.py`, and so the added reads make no difference.

Unfortunately, this means the previous test was a bit too simplistic,
since it only looks for module variable reads and writes. Because of
this, we change the test to be a more traditional "all flow" style
(though restricted to `CfgNode`s).
2021-12-02 17:05:54 +00:00
Nick Rolfe
991d659cb2 Ruby: use unwrap_or_else to construct object only when needed 2021-12-02 16:30:45 +00:00
Nick Rolfe
976faf97d1 Ruby: remove redundant closure 2021-12-02 16:29:59 +00:00
Michael Nebel
19c34be1ea Merge pull request #7297 from michaelnebel/csharp-accessor-flow
C#: Make it possible to define flow for property backing methods.
2021-12-02 16:24:19 +01:00
Michael Nebel
102b5e05e1 Merge pull request #7290 from michaelnebel/csharp-modify-flow-summaries-test
C#: Modify printing of flow summaries in test.
2021-12-02 16:22:47 +01:00
Geoffrey White
2b349b3024 Merge pull request #7295 from geoffw0/cwe260
C++: Add CWE tags to some queries.
2021-12-02 14:41:34 +00:00
intrigus
2c4ccb79a1 Fix QL Doc typos. 2021-12-02 15:30:29 +01:00
Geoffrey White
3043ac850c C++: Update security-severity tags. 2021-12-02 14:04:49 +00:00
Michael Nebel
f6c36b469a C#: Include test case for override of property. 2021-12-02 15:04:01 +01:00
Michael Nebel
f190d60912 C#: Make it possible to describe flow for properties using their backing methods. 2021-12-02 15:02:22 +01:00
Geoffrey White
eccba57536 C++: Add CWE-327 tag to cpp/boost/use-of-deprecated-hardcoded-security-protocol. 2021-12-02 12:32:14 +00:00
Geoffrey White
7aa6c62050 C++: Add CWE-326 tag to cpp/boost/tls-settings-misconfiguration. 2021-12-02 12:29:42 +00:00
Nick Rolfe
05415768c9 Merge remote-tracking branch 'origin/main' into nickrolfe/regexp_g_anchor 2021-12-02 12:07:13 +00:00
yoff
f10f053c36 Merge pull request #7228 from RasmusWL/fastapi-improvements
Python: FastAPI improvements
2021-12-02 12:58:53 +01:00
Geoffrey White
913d8361ba C++: Add CWE-260 tag to cpp/cleartext-storage-file. 2021-12-02 11:54:51 +00:00
yoff
4609b2060a Merge pull request #7217 from RasmusWL/more-path-injection-fps
Python: Add `x in <var>` test for StringConstCompare
2021-12-02 12:35:33 +01:00
Michael Nebel
8f3be9fbfd C#: Update flow summaries test according to new printing format. 2021-12-02 11:28:06 +01:00
Michael Nebel
edf7724579 C#: Remove trailing whitespace after comma, when priting callable in CSV format. 2021-12-02 11:24:42 +01:00
Michael Nebel
37644d30d2 Merge pull request #7281 from michaelnebel/csharp-flowsummaries-filtered
C#: Filtered flow summaries
2021-12-02 11:23:36 +01:00
Erik Krogh Kristensen
6327fced6f remove paths without unmatched returns from polynomial-redos 2021-12-02 10:03:28 +01:00
Michael Nebel
ad281c0365 C#: Sync FlowSummaryImpl files. 2021-12-02 09:03:00 +01:00
Michael Nebel
a8f673ffa4 C#: Add a test that only prints 'base' flow summaries. 2021-12-02 09:03:00 +01:00
Michael Nebel
e08c734c40 C#: Refactoring to allow override of the flow summaries reported by a test. 2021-12-02 08:54:59 +01:00
Michael Nebel
55c17f453f Merge pull request #7280 from michaelnebel/csharp-newtonsoft-flowsummary
C#: Include the NewtonSoft.JSon stubs in the flow summaries test.
2021-12-02 08:47:58 +01:00
github-actions[bot]
87b968f337 Post-release preparation 2.7.3 2021-12-02 00:46:55 +00:00
Mathias Vorreiter Pedersen
9f8326a3fa Merge pull request #7243 from geoffw0/sslquery2
C++: New query for SSL certificates not checked
2021-12-01 15:02:19 +00:00
Erik Krogh Kristensen
a077345227 Merge pull request #7180 from erik-krogh/apiLabel2
JS: Make the edges of API-graphs into IPA types
2021-12-01 15:33:04 +01:00
Erik Krogh Kristensen
73f2f52ed8 use the TYPE_ONLY_IMPORT context 2021-12-01 14:54:16 +01:00
Erik Krogh Kristensen
739906b60c rename @import_or_export_declaration to @type_keyword_operand 2021-12-01 14:47:11 +01:00
Michael Nebel
9e10aee8a1 C#: Update the flow summaries test. 2021-12-01 14:34:32 +01:00
Michael Nebel
cc2914be3c C#: Include NewtonSoft.Json stubs into the flow summaries test. 2021-12-01 14:34:04 +01:00
Erik Krogh Kristensen
de53727ab3 remove spurious whitespace
Co-authored-by: Asger F <asgerf@github.com>
2021-12-01 14:29:57 +01:00
Erik Krogh Kristensen
0a3d62c92a rename mod -> module 2021-12-01 13:48:16 +01:00
Erik Krogh Kristensen
148da611c6 make the ApiLabel class non-abstract 2021-12-01 13:45:52 +01:00
Tom Hvitved
aad55ffbd6 Merge pull request #7279 from hvitved/csharp/json-net-fix-summaries
C#: Fix `Newtonsoft.Json.JsonSerializer.{Deserialize,Serialize}` summaries
2021-12-01 13:15:10 +01:00
Michael Nebel
75f9a947b3 Merge pull request #7257 from michaelnebel/csharp-nuget-packages
C#: Use .NET Core Nuget package stub i test
2021-12-01 13:04:24 +01:00
Michael Nebel
ed706d9bc1 Merge pull request #7269 from michaelnebel/chspar-nuget-stub-script
C#: Update the make_stubs_nuget script
2021-12-01 13:04:02 +01:00
Arthur Baars
e41cd810d3 Merge pull request #7154 from aibaars/ruby-pattern-matching
Ruby: pattern matching
2021-12-01 12:47:22 +01:00
Tom Hvitved
93e291cb3e C#: Fix Newtonsoft.Json.JsonSerializer.{Deserialize,Serialize} summaries 2021-12-01 11:41:16 +01:00
Anders Schack-Mulligen
cde853c095 Merge pull request #7270 from aschackmull/dataflow/stage2-refactor
Dataflow: Stage 2 refactor
2021-12-01 11:09:08 +01:00
haby0
6742beae1b use <code> tags 2021-12-01 16:24:46 +08:00
Tom Hvitved
31374b485c Data flow: Update documentation 2021-12-01 09:01:06 +01:00
Tom Hvitved
e410244fe0 Python: Implement ParameterPosition et al 2021-12-01 08:51:22 +01:00
Tom Hvitved
bb8f4bb7c1 Ruby: Implement ParameterPosition et al 2021-12-01 08:51:22 +01:00
Tom Hvitved
ae6501d906 Java: Implement ParameterPosition et al 2021-12-01 08:51:22 +01:00
haby0
08be8edbce Modify according to suggestions 2021-12-01 11:57:57 +08:00
Andrew Eisenberg
ddd4ccbb4b Merge pull request #7274 from github/aeisenberg/add-version-policy
Add a version policy
2021-11-30 14:51:30 -08:00
Andrew Eisenberg
ff030534ff Add a version policy
Handles the post release process.
2021-11-30 14:47:48 -08:00
Dave Bartolomeo
b42295801b Merge pull request #7271 from github/release-prep/2.7.3
Release preparation for version 2.7.3
2021-11-30 17:29:46 -05:00
github-actions[bot]
337ce65fe5 Release preparation for version 2.7.3 2021-11-30 20:39:35 +00:00
Geoffrey White
4b221bd964 C++: Use guard.controls. 2021-11-30 15:44:48 +00:00
Michael Nebel
186ba428cf C#: Remove workdir as error message when format fails. 2021-11-30 15:57:53 +01:00
Michael Nebel
1243d40bb2 Revert "C#: Update the stub for Microsoft.NETCore.App by creating as a dependency for NewtonSoft.JSon"
This reverts commit 8a6a8fc28a.
2021-11-30 15:49:31 +01:00
Tom Hvitved
35a67845cf C++: Implement ParameterPosition et al 2021-11-30 15:34:16 +01:00
Michael Nebel
59b71df2d6 C#: Use stubs for the CWE-601 testcase. 2021-11-30 15:32:19 +01:00
Michael Nebel
0b4d0d2772 C#: Use stubs for the CWE-838 testcase 2021-11-30 15:32:19 +01:00
Michael Nebel
bab8cfb62a C# Generate stubs for System.Data.SqlClient 2021-11-30 15:32:19 +01:00
Michael Nebel
a5b6889478 C# Update flow summaries test. 2021-11-30 15:32:19 +01:00
Michael Nebel
5dd2d20176 C#: Remove overlapping declaration of System.Web.HttpUtility 2021-11-30 15:32:18 +01:00
Michael Nebel
7d6664f14d C#: Use NuGet package generated stubs for dependencies for flow summaries test 2021-11-30 15:32:18 +01:00
Tom Hvitved
540ecf3c21 Data flow: Sync files 2021-11-30 15:20:20 +01:00
Tom Hvitved
755085e9fe C#: Introduce ParameterPosition and ArgumentPosition 2021-11-30 15:20:20 +01:00
Michael Nebel
2589034242 C#: Execute commands with the tempDir as the working directory 2021-11-30 14:42:21 +01:00
Arthur Baars
830908b5c8 Address comments 2021-11-30 13:57:18 +01:00
Anders Schack-Mulligen
3e914ef2ff Dataflow: Sync. 2021-11-30 13:52:52 +01:00
Anders Schack-Mulligen
fc05825c73 Dataflow: Make stage 2 equal to stages 3 and 4. 2021-11-30 13:52:31 +01:00
Michael Nebel
8a6a8fc28a C#: Update the stub for Microsoft.NETCore.App by creating as a dependency for NewtonSoft.JSon 2021-11-30 13:29:35 +01:00
Michael Nebel
0619453c2f C#: Explicitly set .NET 5.0 as target framework in class lib and hardcode compilation to use version 5.0.402 of the SDK 2021-11-30 13:28:48 +01:00
Paolo Tranquilli
b40c77d419 Merge pull request #7267 from github/redsun82/cpp-overrunning-write-precision-split
C++: add some more range analysis tests
2021-11-30 12:54:48 +01:00
Paolo Tranquilli
3f218c903b C++: add some more range analysis tests
Add more covering for integer conversions and some unsigned bit
manipulation.
2021-11-30 11:29:02 +00:00
Geoffrey White
8f270b665c C++: Fix test comments. 2021-11-30 08:56:24 +00:00
Tony Torralba
c91b6f7ce9 Merge pull request #7266 from github/workflow/coverage/update
Update CSV framework coverage reports
2021-11-30 09:07:09 +01:00
Mathias Vorreiter Pedersen
f4555ed1a2 Merge pull request #7242 from geoffw0/sslquery 2021-11-30 07:01:33 +00:00
github-actions[bot]
66e086f92f Add changed framework coverage reports 2021-11-30 00:09:58 +00:00
Dave Bartolomeo
9f6c0991cf Catch up with recent change notes 2021-11-29 16:41:18 -05:00
Dave Bartolomeo
5ed9029143 Move change notes to correct directories 2021-11-29 16:31:11 -05:00
Dave Bartolomeo
75fb47c76f Ruby change notes 2021-11-29 16:17:19 -05:00
Dave Bartolomeo
cd8a10d0a5 Python change notes 2021-11-29 16:17:05 -05:00
Dave Bartolomeo
96deddf053 JavaScript change notes 2021-11-29 16:16:30 -05:00
Dave Bartolomeo
452685bb66 Fix change note path 2021-11-29 16:11:34 -05:00
Dave Bartolomeo
310ef79fbd C++ change notes 2021-11-29 16:10:33 -05:00
Dave Bartolomeo
d0dac03bad Manually bump versions 2021-11-29 14:21:08 -05:00
Dave Bartolomeo
2dfcd1dd9c Add groups property
Also removed versions from test packs
2021-11-29 14:15:53 -05:00
Chris Smowton
27f40e08e5 Merge pull request #7007 from JLLeitschuh/feat/JLL/improve_ratpack_support
Java: Ratpack HTTP Framework Additional Modeling
2021-11-29 16:20:53 +00:00
Rasmus Wriedt Larsen
d557f6fd2e Merge pull request #7101 from RasmusWL/python-ids
Python: Fix some query-ids
2021-11-29 16:12:57 +01:00
yoff
41b7922c7d Merge pull request #7089 from RasmusWL/redos-cwe-1333
Python/C#: Add CWE-1333 to redos queries
2021-11-29 16:09:39 +01:00
yoff
19802ccb73 Merge pull request #7046 from RasmusWL/django-own-json-response
Python: Add test with custom django json response (FP)
2021-11-29 16:05:20 +01:00
Arthur Baars
1e026ef45e AST: merge Case and CaseMatch classes 2021-11-29 16:00:17 +01:00
yoff
e63f9141e5 Merge pull request #7233 from RasmusWL/fix-cleartext-logging-cwes
JS/Py: Fix cleartext logging CWEs
2021-11-29 15:58:10 +01:00
Rasmus Wriedt Larsen
cbd7434a7e Python: Add modeling of tempfile module 2021-11-29 15:08:36 +01:00
Rasmus Wriedt Larsen
b68538376c Python: Add tests of tempfile module 2021-11-29 15:08:36 +01:00
Rasmus Wriedt Larsen
3bcf6d68ce Python: Refactor os FileSystemAccess change-note
I think it's more readable to have only one to cover all of these
changes, even though they came in through different PRs.
2021-11-29 15:08:18 +01:00
Arthur Baars
f8a62c4c82 Address comments 2021-11-29 15:06:16 +01:00
Rasmus Wriedt Larsen
58f92764f7 Python: Model more file access from os module 2021-11-29 14:54:02 +01:00
Rasmus Wriedt Larsen
fd23fa94a5 Python: Remove dubious fstat* modeling
These operate on file descriptors, and not on paths. file descriptors
doesn't fit into the rest of our modeling, so I would rather remove them
than to make it look like it's properly handled.

I also did not include any of the functions that work on file
descriptors when looking through all of `os`. So this keeps everything
consistent at least ;)
2021-11-29 14:54:02 +01:00
Rasmus Wriedt Larsen
e79b8f3e23 Python: Treat os.exec*, os.spawn*, and os.posix_spawn* as FileSystemAccess 2021-11-29 14:54:02 +01:00
Rasmus Wriedt Larsen
d2d5cce787 Python: Recognize keyword arguments for os.*spawn* calls 2021-11-29 14:54:02 +01:00
Rasmus Wriedt Larsen
14590436f9 Python: Expand tests for os.exec*, os.spawn*, and os.posix_spawn* 2021-11-29 14:54:02 +01:00
Rasmus Wriedt Larsen
50d3592ad3 Python: Add more complete tests of os module
I went through https://docs.python.org/3.10/library/os.html in order,
and added all the functions that works on paths.

`lstat` and `statvfs` were already modeled, but did not have any tests.
2021-11-29 14:54:02 +01:00
Rasmus Wriedt Larsen
a91208fd2c Python: Fix kwarg modeling for os.path.isdir 2021-11-29 14:54:02 +01:00
Rasmus Wriedt Larsen
36f14b31bc Python: Add explicit tests for kwargs
I also renamed the arguments to match what the keyword argument is
called. It doesn't matter too much for these specific tests, but for the
tests I'm about to add, it makes things a lot easier to get an overview
of.

Oh, and a test failure :O
2021-11-29 14:54:02 +01:00
Rasmus Wriedt Larsen
82602014ad Python: Minor refactor to use os.path.<func>
Since that's the idiomatic way to use this module
2021-11-29 14:54:02 +01:00
Geoffrey White
88fb1a18cb C++: Correct the doc. 2021-11-29 13:09:12 +00:00
Erik Krogh Kristensen
fdcc144a98 add test for import assertions 2021-11-29 13:51:28 +01:00
Erik Krogh Kristensen
591aeff906 add TypeScript test for new private field syntax 2021-11-29 13:51:28 +01:00
Erik Krogh Kristensen
19bbe6d276 add JavaScript support for new private fields syntax 2021-11-29 13:51:25 +01:00
Erik Krogh Kristensen
d1a7feebc4 disable import resolution on type-only import specifiers 2021-11-29 13:49:10 +01:00
Erik Krogh Kristensen
d946802057 add support for type-only import specifiers 2021-11-29 13:49:10 +01:00
Erik Krogh Kristensen
57399b733e add test for String types as Discriminants 2021-11-29 13:49:10 +01:00
Erik Krogh Kristensen
0e890fd788 add test for the Awaited type 2021-11-29 13:49:10 +01:00
Erik Krogh Kristensen
eef3905c46 update expected output. The TypeScript compiler now emits types in more cases 2021-11-29 13:49:10 +01:00
Erik Krogh Kristensen
9ce248c829 update to TypeScript 4.5.2 2021-11-29 13:49:10 +01:00
Erik Krogh Kristensen
c13cad7e87 Merge branch 'main' into apiLabel2 2021-11-29 13:43:11 +01:00
Geoffrey White
d79337774d Update cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.qhelp
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2021-11-29 12:33:05 +00:00
Michael Nebel
e476cde985 Merge pull request #7255 from michaelnebel/csharp-effecpublic-flowsummary
C#: Only include effectively public declarations in flow summaries
2021-11-29 12:52:26 +01:00
Michael Nebel
e1539889ef C#: Update flow summaries tests 2021-11-29 11:35:02 +01:00
Michael Nebel
e24b15bbe7 C#: Only create flow summaries for declarations that are effectively public 2021-11-29 11:34:21 +01:00
Michael Nebel
9239d4042e Merge pull request #7230 from michaelnebel/csharp-update-netcoreapp-stub
C#: Update the Microsoft.NETCore.App stub
2021-11-29 10:08:59 +01:00
Tom Hvitved
fdc94365b4 Merge pull request #7178 from michaelnebel/csharp-flowsummary-pp-csv
C#: Initial implementation of csv printing in FlowSummaries test
2021-11-29 09:59:33 +01:00
haby0
db04a0dadf New model: SQL injection in MyBatis annotations 2021-11-28 14:43:57 +08:00
Erik Krogh Kristensen
74158f1e3a revert explicit-this that caused non-monotonic recursion 2021-11-26 21:37:46 +01:00
Taus
09a11f4166 Python: Update ImpliesDataflow test
Turns out that now we can resolve the convoluted imports. Hurray!
2021-11-26 14:47:25 +00:00
Michael Nebel
d4f3a6d4bb C#: Review comments. Keep the TContent type pribate 2021-11-26 15:38:33 +01:00
Taus
6c3aabe1df Python: Support flow through import *
Adds result for `ModuleVariableNode::getARead` corresponding to reads
that go through (chains of) `import *`.

This required a bit of a change to _which_ module variables we define.
Previously, we only included variables that were accessed elsewhere in
the same file, but now we must ensure to also include variables that may
be accessed through `import *`.
2021-11-26 13:49:08 +00:00
Taus
c3e495efe9 Python: Refactor built-ins and import * logic
Moves this from the API graphs implementation into separate files.
2021-11-26 13:49:08 +00:00
Taus
03b6ee3833 Python: Add import * test
This test shows off a few things:

- transitive chains of `import *`
- multiple modules exporting the same name (to test for cross-talk)
2021-11-26 13:49:08 +00:00
Erik Krogh Kristensen
6ff8d4de5c add all remaining explicit this 2021-11-26 13:50:10 +01:00
Anders Schack-Mulligen
00ee34c0a0 Merge pull request #7237 from hvitved/dataflow/consistency-config
Data flow: Introduce `ConsistencyConfiguration` class
2021-11-26 12:49:25 +01:00
Anders Schack-Mulligen
57fd397cb3 Merge pull request #7239 from smowton/smowton/fix/useless-comparison-surrogates
Range analysis and useless-comparison query: don't treat all unicode surrogates as if they are U+FFFD
2021-11-26 09:00:36 +01:00
Chris Smowton
d3a4dadc7d Merge pull request #7240 from smowton/smowton/admin/derecognise-xxe-secure-processing
Note that FEATURE_SECURE_PROCESSING isn't a sufficient defence against XXE
2021-11-25 19:31:06 +00:00
Henry Mercer
aa9a8a0e22 Merge pull request #7244 from github/henrymercer/atm-specify-ml-models-globs
JS: [Internal only] Add ML models specification to ATM query pack definition
2021-11-25 18:20:45 +00:00
Chris Smowton
36bb84d97f Copyedit change note 2021-11-25 12:55:55 -05:00
Jonathan Leitschuh
1ddf5fb133 Java: Ratpack HTTP Framework Additional Modeling
Adds models for `ratpack.func.Pair`, and `ratpack.exec.Result`.
Improve moels for `ratpack.exec.Promise`.

Signed-off-by: Jonathan Leitschuh <Jonathan.Leitschuh@gmail.com>
2021-11-25 12:55:32 -05:00
Henry Mercer
29eb66d772 JS: Add ML models to .gitignore 2021-11-25 17:06:37 +00:00
Henry Mercer
2af509595b JS: Add ML models specification to ATM query pack definition
This will allow us to resolve the ATM machine learning models that will
be distributed within this pack.
2021-11-25 16:42:38 +00:00
Chris Smowton
7ac5791c49 Update charLiterals.expected 2021-11-25 16:13:06 +00:00
Geoffrey White
f96968975b C++: Change note. 2021-11-25 15:49:41 +00:00
Geoffrey White
e98ab5d2c2 C++: Add security-severity tag and provisional precision. 2021-11-25 15:49:40 +00:00
Geoffrey White
e9ce29664e C++: Qldoc. 2021-11-25 15:48:12 +00:00
Chris Smowton
ce63549425 Apply review comments 2021-11-25 15:20:35 +00:00
Chris Smowton
db39c0b8be CharacterLiteral.getCodePointValue: fix handling of surrogates 2021-11-25 14:07:21 +00:00
Geoffrey White
1d358c5f77 C++: Change note. 2021-11-25 14:04:47 +00:00
Anders Schack-Mulligen
a06642944f Merge pull request #7232 from aschackmull/dataflow/perf
Data flow: Performance tuning
2021-11-25 15:01:01 +01:00
Geoffrey White
f5b40731d6 C++: Add security-severity tag and provisional precision. 2021-11-25 13:59:21 +00:00
Arthur Baars
e801d9636a Ruby: add ruby/ruby to the dataset-measure CI job 2021-11-25 14:10:15 +01:00
Tom Hvitved
dc0b0445ed Merge pull request #7185 from hvitved/csharp/ssa/consistency-queries
C#: Enable SSA consistency queries
2021-11-25 14:04:01 +01:00
Chris Smowton
9540beeda9 Update java/ql/test/query-tests/security/CWE-611/DocumentBuilderTests.java
Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com>
2021-11-25 12:52:08 +00:00
Arthur Baars
8b0bc677f4 Remove PatternGuard class 2021-11-25 13:50:19 +01:00
Arthur Baars
dca1e34cd8 Temporarily allow CFG inconsistencies 2021-11-25 13:42:59 +01:00
Arthur Baars
16e1e97ff0 Add test data for case-in expressions 2021-11-25 13:25:33 +01:00
Arthur Baars
af4c3122ca Test case for **nil parameter 2021-11-25 13:25:00 +01:00
Arthur Baars
078a2aa03b Update AST library 2021-11-25 13:24:51 +01:00
Chris Smowton
9eb9eb606e Note that FEATURE_SECURE_PROCESSING isn't a sufficient defence against XXE 2021-11-25 12:22:48 +00:00
Arthur Baars
ec0bd24b64 Update diagnostic tests 2021-11-25 12:55:50 +01:00
Arthur Baars
5b560b12e9 Create upgrade script 2021-11-25 12:55:43 +01:00
Anders Schack-Mulligen
609d6011a2 Merge pull request #7229 from smowton/smowton/admin/document-xxe-sanitisation-policy
Document XXE sanitisation policy
2021-11-25 10:55:25 +01:00
Tom Hvitved
6cb00992e8 Data flow: Introduce ConsistencyConfiguration class 2021-11-25 10:01:47 +01:00
haby0
04a3f76a8b Eliminate false positives of Mybatis Configuration Variable 2021-11-25 15:47:37 +08:00
haby0
d36a7ed10e add test case 2021-11-25 15:47:32 +08:00
haby0
99c8b291b2 add sink 2021-11-25 15:47:32 +08:00
haby0
b8732859de Add isSanitizerGuard, verify file path 2021-11-25 15:47:31 +08:00
haby0
31400df0d4 Modify sink and improve SQL injection detection 2021-11-25 15:47:30 +08:00
haby0
69690a2509 Modify sinks 2021-11-25 15:47:30 +08:00
haby0
4438f8c58c Add MyBatis Mapper Sql Injection 2021-11-25 15:47:29 +08:00
CodeQL CI
d3da790191 Merge pull request #6873 from erik-krogh/explicit-this
Approved by esbena
2021-11-24 15:23:35 -08:00
Chris Smowton
3c8f6e3c07 Merge pull request #6717 from luchua-bc/java/thread-resource-abuse
Java: CWE-400 - Query to detect uncontrolled thread resource consumption
2021-11-24 18:59:41 +00:00
Geoffrey White
4c5faaf985 C++: Autoformat result not checked query. 2021-11-24 18:26:39 +00:00
Geoffrey White
8abaf1247a C++: Clean up result not checked query. 2021-11-24 18:26:39 +00:00
Geoffrey White
5ffbf563b8 C++: Add metadata for result not checked query. 2021-11-24 18:26:38 +00:00
Geoffrey White
72a03257e7 C++: Add qhelp for result not checked query. 2021-11-24 18:26:38 +00:00
Geoffrey White
5eb814fd8b C++: Prototype SSL result not checked query. 2021-11-24 18:26:37 +00:00
Geoffrey White
7869733ab5 C++: Autoformat result conflation query. 2021-11-24 18:25:58 +00:00
Geoffrey White
88b6bd9478 C++: Switch result conflation query to a slightly simpler dataflow-only approach. 2021-11-24 18:25:57 +00:00
Geoffrey White
ce2b86b9e3 C++: Add metadata for result conflation query. 2021-11-24 18:25:57 +00:00
Geoffrey White
2eae6a3e9a C++: Add qhelp for result conflation query. 2021-11-24 18:25:56 +00:00
Geoffrey White
6afcbce421 C++: Prototype SSL result conflation query. 2021-11-24 18:22:24 +00:00
Arthur Baars
5d0dfe8c04 Re-generate library and dbscheme 2021-11-24 17:18:04 +01:00
Arthur Baars
e7524dea69 Update tree-sitter-ruby 2021-11-24 17:18:03 +01:00
Arthur Baars
4b3b1d2a8b Merge pull request #7222 from aibaars/ruby-ci-fix
Ruby: fix CI jobs after removal of `.codeql-manifest.json`
2021-11-24 17:16:52 +01:00
Erik Krogh Kristensen
1e752f305d apply the explicit this patch to new code 2021-11-24 15:26:19 +01:00
Erik Krogh Kristensen
08ce03cd93 Merge branch 'main' into explicit-this 2021-11-24 15:24:58 +01:00
Erik Krogh Kristensen
3bab8c6d1d Merge pull request #7173 from erik-krogh/getRubyInSync
JS/PY/RB: get ReDoSUtil in sync for ruby
2021-11-24 15:20:23 +01:00
Rasmus Wriedt Larsen
651a76c9ce Python: Add CWE-532 to CleartextLogging
Relevant for this query:

CWE-532: Insertion of Sensitive Information into Log File

> While logging all information may be helpful during development
> stages, it is important that logging levels be set appropriately
> before a product ships so that sensitive user data and system
> information are not accidentally exposed to potential attackers.

See https://cwe.mitre.org/data/definitions/532.html

JS also did this recently: https://github.com/github/codeql/pull/7103
2021-11-24 14:59:52 +01:00
Rasmus Wriedt Larsen
c05ffd4d00 JS/PY: Remove CWE-315 form CleartextLogging
Since it is not relevant for this query:

CWE-315: Cleartext Storage of Sensitive Information in a Cookie

See https://cwe.mitre.org/data/definitions/315.html
2021-11-24 14:59:18 +01:00
Anders Schack-Mulligen
7ca3407c86 Dataflow: Sync. 2021-11-24 14:43:00 +01:00
Anders Schack-Mulligen
a7ec0fa900 Dataflow: Remove more disjunction-induced tuple duplication. 2021-11-24 14:39:49 +01:00
Michael Nebel
b9d0a60ce7 C#: Addressed review comments from hvitved 2021-11-24 14:35:52 +01:00
luchua-bc
b0031a0d85 Add local input test case and update qldoc 2021-11-24 13:30:50 +00:00
Tom Hvitved
1d1780b30f C#: Fix bug in getEnclosingCallable 2021-11-24 14:24:01 +01:00
Rasmus Wriedt Larsen
7dde52ced2 Merge pull request #7131 from RasmusWL/wsgiref.simple_server
Python: Model `wsgiref.simple_server` applications
2021-11-24 14:22:23 +01:00
Anders Schack-Mulligen
4efdcc22a2 Dataflow: Improve barrier handling. 2021-11-24 14:17:05 +01:00
Tom Hvitved
f85fa87f69 C#: Add test that illustrates problem with getEnclosingCallable 2021-11-24 13:59:29 +01:00
Rasmus Wriedt Larsen
2a5e0a3b77 Merge pull request #7145 from RasmusWL/remove-owasp-tags
Python/Ruby: Remove owasp tags
2021-11-24 13:56:48 +01:00
Rasmus Wriedt Larsen
e2652591a5 Python: Change perf fix PoorMansFunctionResolution
Thanks @yoff, this leaves us with the following evaluation, which looks
very close to the one in the other fix (but with cleaner implementation)
-- both at 688k max tuples (although numbers are not exactly the same).

```
[2021-11-24 13:48:40] (14s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass#ff/2@e5f05asv after 74ms:
                      47493  ~3%     {3} r1 = JOIN Class::Class::getAMethod_dispred#ff WITH py_Classes ON FIRST 1 OUTPUT Lhs.1, 0, Lhs.0
                      47335  ~0%     {2} r2 = JOIN r1 WITH AstGenerated::Function_::getArg_dispred#fff ON FIRST 2 OUTPUT Rhs.2, Lhs.2
                      46683  ~0%     {2} r3 = JOIN r2 WITH DataFlowPublic::ParameterNode::getParameter_dispred#fb_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1
                      259968 ~4%     {2} r4 = JOIN r3 WITH LocalSources::Cached::hasLocalSource#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1
                      161985 ~0%     {3} r5 = JOIN r4 WITH Attributes::AttrRef::accesses_dispred#bff_102#join_rhs ON FIRST 1 OUTPUT Rhs.1 'result', Lhs.1, Rhs.2
                      161985 ~2%     {3} r6 = JOIN r5 WITH Attributes::AttrRead#class#f ON FIRST 1 OUTPUT Lhs.2, Lhs.1, Lhs.0 'result'
                      688766 ~0%     {3} r7 = JOIN r6 WITH Function::Function::getName_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.1, Rhs.1 'func', Lhs.2 'result'
                      20928  ~0%     {2} r8 = JOIN r7 WITH Class::Class::getAMethod_dispred#ff ON FIRST 2 OUTPUT Lhs.1 'func', Lhs.2 'result'
                                     return r8
```
2021-11-24 13:52:05 +01:00
Rasmus Wriedt Larsen
1411804e58 Python: Allow custom fastapi.APIRouter subclasses 2021-11-24 13:46:38 +01:00
Tom Hvitved
1d654d1eac C#: Restrict refReadBeforeWrite 2021-11-24 13:43:14 +01:00
Tom Hvitved
1739673202 C#: Enable SSA consistency queries 2021-11-24 13:43:14 +01:00
Chris Smowton
c74eac4930 Remove needless casts 2021-11-24 12:18:05 +00:00
Chris Smowton
cec91c4831 Update ThreadResourceAbuse.qhelp 2021-11-24 12:15:48 +00:00
Chris Smowton
5101a8e9f3 Fix qhelp test 2021-11-24 12:12:56 +00:00
Chris Smowton
136ecaf49a Abbreviate qhelp example 2021-11-24 12:12:22 +00:00
Michael Nebel
c3996b00d5 C#: Update the Microsoft.NETCore.App stub 2021-11-24 13:09:06 +01:00
Chris Smowton
120f2045cd Document XXE sanitisation policy 2021-11-24 12:03:28 +00:00
Mathias Vorreiter Pedersen
6d9cea90cb Merge pull request #7226 from MathiasVP/shorter-ir-dataflow-paths
C++: Hide some IR dataflow nodes
2021-11-24 11:13:52 +00:00
Michael Nebel
a3ca9ad27d C#: Sync flow summary implementation files and implement specific parts for ruby and java 2021-11-24 12:09:20 +01:00
Michael Nebel
e153a65216 C#: Update flow summaries test for EntityFramework to print results in CSV syntax 2021-11-24 12:09:20 +01:00
Michael Nebel
914d3d86af C#: Update flow summaries test to print results in CSV syntax 2021-11-24 12:09:20 +01:00
Michael Nebel
3a7d51d2ee C#: Don't throw away ReturnKind information, when printing flow summaries. Note that any non NormalReturnKind printed summary will not be in the flow summary CSV language 2021-11-24 12:09:20 +01:00
Michael Nebel
e607c51292 C#: Initial implementation of csv printing in FlowSummaries test 2021-11-24 12:09:20 +01:00
Rasmus Wriedt Larsen
47448d9efc Python: Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2021-11-24 12:02:12 +01:00
Mathias Vorreiter Pedersen
6c7a01d3d5 C++: Add some comments to the two 'flowThrough' predicates. 2021-11-24 10:50:44 +00:00
Rasmus Wriedt Larsen
d493cfdf3a Python: Model FastAPI FileResponse as FileSystemAccess
This was an oversight from our initial FastAPI modeling work.
2021-11-24 11:44:51 +01:00
yoff
f9729bccef Merge pull request #7143 from RasmusWL/path-improvements
Python: Model `posixpath` and `os.stat`
2021-11-24 11:36:06 +01:00
Anders Schack-Mulligen
a3b263ee6e Merge pull request #7181 from bmuskalla/coverageAsDiagnostics
Java: Add diagnostic query for framework coverage
2021-11-24 10:57:50 +01:00
Rasmus Wriedt Larsen
b2611fe198 Merge branch 'main' into redos-cwe-1333 2021-11-24 10:42:43 +01:00
Mathias Vorreiter Pedersen
2e7ddb479e C++: Accept test changes. 2021-11-24 09:41:00 +00:00
Mathias Vorreiter Pedersen
4cbfc306ac C++: Hide dataflow nodes if they're just used for flow-through for read steps or store steps. 2021-11-24 08:01:44 +00:00
Arthur Baars
133ec2e4af Fix CI jobs 2021-11-23 22:03:01 +01:00
Erik Krogh Kristensen
87a1ccd428 Merge branch 'main' into getRubyInSync 2021-11-23 20:20:37 +01:00
luchua-bc
e56737e007 Use value step to optimize the taint step and add a test case for Apache file upload listener 2021-11-23 17:15:28 +00:00
Mathias Vorreiter Pedersen
8c9e817c0d Merge pull request #7188 from github/redsun82/fix-operand-location
C++: take IR Operand locations from definitions
2021-11-23 16:32:06 +00:00
Nick Rolfe
bb38c4d6fd Merge pull request #6978 from github/nickrolfe/regex_injection
Ruby: add regex injection query
2021-11-23 16:22:35 +00:00
Nick Rolfe
1a90b388a9 Merge remote-tracking branch 'origin/main' into nickrolfe/regex_injection 2021-11-23 15:42:05 +00:00
Paolo Tranquilli
055017de49 fix how non existing locations are accounted for 2021-11-23 15:28:16 +00:00
Paolo Tranquilli
9538ac73e4 account for non-existing locations 2021-11-23 15:28:16 +00:00
Paolo Tranquilli
d626745ab1 fix ThisArgumentOperand location
The correct check to do to choose between using `getAnyDef` and `getUse`
is to check whether the location is an instance of UknonwnLocation.
2021-11-23 15:28:16 +00:00
Paolo Tranquilli
e99a040884 implement review suggestions 2021-11-23 15:28:16 +00:00
Paolo Tranquilli
8b44d5c39e sync files 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
30805d964c add ThisArgumentOperand special case 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
9b818a04f2 sync 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
0bb11fa371 fix PrintAST test run
The refactored shouldDumpFunction was now rejecting functions without a
location. This is fixed now.
2021-11-23 15:28:15 +00:00
Paolo Tranquilli
0547e4ccf2 update further test with new locations 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
d4e80c664e replace shouldDump -> shouldDumpLocation 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
4498657384 Apply suggestions from code review
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2021-11-23 15:28:15 +00:00
Paolo Tranquilli
28806fe5f4 update test results after operand location changes 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
6072ccd81d auto-format 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
0ff9520575 ...and syncing files again 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
b5165e3692 C++: more fine-grained Operand location change
Only RegisterOperands need the change, with the notable exception of
ThisArgumentOperand.
2021-11-23 15:28:15 +00:00
Paolo Tranquilli
5202f963dd C++: sync Operand source 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
74c0197544 C++: take IR Operand locations from definitions
Previously Operand's getLocation would take it from the Operand use.
This lead to slightly confusing query results, where for example an
issue related to a call argument would highlight the function part of
the call instead of the parameter.
2021-11-23 15:28:15 +00:00
Tom Hvitved
83d204d7a8 Merge pull request #7218 from hvitved/ssa/fix-consistency-tests
Ruby: Fix SSA consistency tests + CFG bug
2021-11-23 16:24:41 +01:00
Tom Hvitved
4d918b5e5f Ruby: Fix CFG splitting logic for ensure blocks with loops 2021-11-23 15:21:43 +01:00
Anders Schack-Mulligen
822890f2bd Dataflow: Remove disjunction-induced tuple duplication. 2021-11-23 15:05:24 +01:00
Geoffrey White
3e1164f82e Merge pull request #7109 from MathiasVP/remove-reference-to-as-load
C++: Don't interpret 'ReferenceToInstruction' as a load
2021-11-23 13:56:22 +00:00
Alex Ford
055641e684 Merge pull request #7062 from github/ruby/rails-csrf
Ruby: Add `rb/csrf-protection-disabled` query
2021-11-23 13:46:42 +00:00
Anders Schack-Mulligen
f5f67dd11a Dataflow: Pull ccc.matchesCall(call) from the recursive loop. 2021-11-23 14:35:33 +01:00
Taus
8cccee6eba Merge pull request #6972 from yoff/python/promote-redos
Python: Promote ReDoS queries
2021-11-23 14:02:09 +01:00
Tom Hvitved
0bd587b395 Shared SSA: Sync files 2021-11-23 13:30:37 +01:00
Tom Hvitved
e185e9080c Shared SSA: Fix consistency tests 2021-11-23 13:30:23 +01:00
Erik Krogh Kristensen
b2e40ac603 fix typo in test
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2021-11-23 13:09:22 +01:00
Rasmus Wriedt Larsen
baafd9f8ba Python: Add an other path injection FP
Along with the root cause, which is the `StringConstCompare`
BarrierGuard, that does only allows `in <iterable literal>` and not
`in <variable referencing iterable literal>`
2021-11-23 12:59:15 +01:00
Nick Rolfe
e5f473052d Ruby: add Regexp.{compile,quote} to regex injection test 2021-11-23 11:05:41 +00:00
Anders Schack-Mulligen
e711ba9d18 Dataflow: Remove negation materialization. 2021-11-23 11:35:57 +01:00
Tom Hvitved
9d072a12ed Merge pull request #7098 from github/ruby/desugar-for-1
Ruby: Desugar `for` loops as calls to `each`
2021-11-23 11:35:49 +01:00
Mathias Vorreiter Pedersen
672485ae38 Merge branch 'main' into remove-reference-to-as-load 2021-11-23 10:24:17 +00:00
James Fletcher
21aff99637 Merge pull request #7215 from github/jf205-patch-1
Fix link formatting
2021-11-23 10:03:40 +00:00
Tom Hvitved
dcca5d28bb Merge pull request #7172 from hvitved/ruby/ensure-split-cp
Ruby: Remove CP in `EnsureSplitImpl::exit/3`
2021-11-23 11:02:23 +01:00
Benjamin Muskalla
50518b5622 Fix sum of rows 2021-11-23 10:42:24 +01:00
James Fletcher
b8e8ddf9ae fix link 2021-11-23 08:38:39 +00:00
Anders Schack-Mulligen
a68b55b099 Merge pull request #7208 from hvitved/ruby/restrict-use-use
Ruby: Restrict use-use flow
2021-11-23 09:33:43 +01:00
ihsinme
70081defdc Update FindIncorrectlyUsedExceptions.expected 2021-11-23 09:56:02 +03:00
ihsinme
62ae702e07 Update FindIncorrectlyUsedExceptions.ql 2021-11-23 09:55:43 +03:00
luchua-bc
ed78d39d61 Move duplicate code to the shared library and update qldoc 2021-11-23 03:06:26 +00:00
Henry Mercer
245edd41ff Merge pull request #7186 from github/henrymercer/rename-available-models-predicate
JS: [Internal only] Rename the available ML models external predicate
2021-11-22 18:26:46 +00:00
Nick Rolfe
13459c8afc Ruby: add Regexp.compile as sink for regexp injection query 2021-11-22 17:43:55 +00:00
Nick Rolfe
4b42c4447b Ruby: handle Regexp.quote wherever we handle Regexp.escape 2021-11-22 17:12:01 +00:00
Nick Rolfe
5b11cfe006 Ruby: fix up import path 2021-11-22 17:10:46 +00:00
Nick Rolfe
752b126862 Merge remote-tracking branch 'origin/main' into nickrolfe/regex_injection 2021-11-22 17:05:27 +00:00
Rasmus Wriedt Larsen
eaed870b31 Python: Fix performance problem in PoorMansFunctionResolution
Before these changes:

[2021-11-22 12:02:50] (8s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass#ff/2@cbddf257 after 8.6s:
                      387565   ~0%     {3} r1 = JOIN Attributes::AttrRead#class#f WITH Attributes::AttrRef::accesses_dispred#bff ON FIRST 1 OUTPUT Rhs.2, Lhs.0 'result', Rhs.1
                      6548632  ~0%     {3} r2 = JOIN r1 WITH Function::Function::getName_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'func', Lhs.1 'result', Lhs.2
                      5640480  ~0%     {4} r3 = JOIN r2 WITH Class::Class::getAMethod_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'result', Lhs.2, Lhs.0 'func'
                      55660458 ~0%     {5} r4 = JOIN r3 WITH Class::Class::getAMethod_dispred#ff ON FIRST 1 OUTPUT Rhs.1, 0, Lhs.1 'result', Lhs.2, Lhs.3 'func'
                      55621412 ~0%     {4} r5 = JOIN r4 WITH AstGenerated::Function_::getArg_dispred#fff ON FIRST 2 OUTPUT Rhs.2, Lhs.2 'result', Lhs.3, Lhs.4 'func'
                      54467144 ~0%     {4} r6 = JOIN r5 WITH DataFlowPublic::ParameterNode::getParameter_dispred#fb_10#join_rhs ON FIRST 1 OUTPUT Lhs.2, Rhs.1, Lhs.1 'result', Lhs.3 'func'
                      20928    ~0%     {2} r7 = JOIN r6 WITH LocalSources::Cached::hasLocalSource#ff ON FIRST 2 OUTPUT Lhs.3 'func', Lhs.2 'result'
                                       return r7

With these changes:

[2021-11-22 11:54:25] (415s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper#fff/3@14db70a8 after 75ms:
                      388306 ~0%     {2} r1 = JOIN Attributes::AttrRead#class#f WITH Attributes::AttrRef::getObject_dispred#bf ON FIRST 1 OUTPUT Rhs.1, Lhs.0 'read'
                      379420 ~4%     {2} r2 = JOIN r1 WITH LocalSources::Cached::hasLocalSource#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'read'
                      175082 ~0%     {2} r3 = JOIN r2 WITH DataFlowPublic::ParameterNode#class#fff ON FIRST 1 OUTPUT Rhs.2, Lhs.1 'read'
                      175082 ~2%     {3} r4 = JOIN r3 WITH Essa::ParameterDefinition::getParameter_dispred#ff ON FIRST 1 OUTPUT 0, Rhs.1, Lhs.1 'read'
                      166798 ~0%     {2} r5 = JOIN r4 WITH AstGenerated::Function_::getArg_dispred#fff_120#join_rhs ON FIRST 2 OUTPUT Rhs.2 'func', Lhs.2 'read'
                      162096 ~0%     {3} r6 = JOIN r5 WITH Class::Class::getAMethod_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.0 'func', Rhs.1 'cls', Lhs.1 'read'
                                     return r6

[2021-11-22 11:54:25] (415s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper2#ffff/4@2b60f0s9 after 63ms:
                      162046 ~0%     {3} r1 = SCAN PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper#fff OUTPUT In.2 'read', In.0 'func', In.1 'cls'
                      162046 ~0%     {3} r2 = JOIN r1 WITH Attributes::AttrRead#class#f ON FIRST 1 OUTPUT Lhs.1 'func', Lhs.2 'cls', Lhs.0 'read'
                      162046 ~1%     {3} r3 = JOIN r2 WITH py_Functions ON FIRST 1 OUTPUT Lhs.1 'cls', Lhs.2 'read', Lhs.0 'func'
                      162046 ~0%     {3} r4 = JOIN r3 WITH py_Classes ON FIRST 1 OUTPUT Lhs.1 'read', Lhs.2 'func', Lhs.0 'cls'
                      161935 ~5%     {4} r5 = JOIN r4 WITH Attributes::AttrRef::getAttributeName_dispred#bf ON FIRST 1 OUTPUT Rhs.1, Lhs.0 'read', Lhs.1 'func', Lhs.2 'cls'
                      688526 ~1%     {4} r6 = JOIN r5 WITH Function::Function::getName_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.2 'func', Lhs.3 'cls', Lhs.1 'read', Rhs.1 'readFunction'
                                     return r6

[2021-11-22 11:54:25] (415s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass#ff/2@f73ae6dq after 58ms:
                      688526 ~0%     {4} r1 = SCAN PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper2#ffff OUTPUT In.1, In.0, In.3 'func', In.2 'result'
                      688526 ~0%     {3} r2 = JOIN r1 WITH Class::Class::getAMethod_dispred#ff ON FIRST 2 OUTPUT Rhs.0, Lhs.2 'func', Lhs.3 'result'
                      20913  ~0%     {2} r3 = JOIN r2 WITH Class::Class::getAMethod_dispred#ff ON FIRST 2 OUTPUT Lhs.1 'func', Lhs.2 'result'
                                     return r3

We need the `pragma[only_bind_into]` in getSimpleMethodReferenceWithinClass_helper2, otherwise the tuple counts would look like, which is needlessly big.

[2021-11-22 17:14:34] (2s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper2#ffff/4@5f0505h7 after 711ms:
                      13570510 ~3%     {2} r1 = JOIN Function::Function::getName_dispred#ff_10#join_rhs WITH Attributes::AttrRef::getAttributeName_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'read', Lhs.1 'readFunction'
                      688526   ~1%     {4} r2 = JOIN r1 WITH PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper#fff_201#join_rhs ON FIRST 1 OUTPUT Rhs.1 'func', Rhs.2 'cls', Lhs.0 'read', Lhs.1 'readFunction'
                                       return r2
2021-11-22 17:22:39 +01:00
Arthur Baars
f6baab6399 Merge pull request #7211 from dbartol/dbartol/ruby-workspace
Merge Ruby workspace into root workspace
2021-11-22 16:22:12 +01:00
Alex Ford
68c3c16ab3 Ruby: enable forgery protection checks for development environments 2021-11-22 15:00:32 +00:00
Dave Bartolomeo
186e3755c0 Remove unnecessary path options 2021-11-22 09:50:01 -05:00
Tom Hvitved
da39f15a9d Ruby: Move localFlowStepCommon into LocalFlow and make localSsaFlowStep private 2021-11-22 15:24:24 +01:00
Dave Bartolomeo
522074940d Merge Ruby workspace into root workspace 2021-11-22 09:10:59 -05:00
AlonaHlobina
b60fef88b5 Merge pull request #7206 from github/AlonaHlobina-patch-2
Update query-metadata-style-guide.md
2021-11-22 14:48:46 +01:00
Mathias Vorreiter Pedersen
21167f4b67 C++: Accept test changes. 2021-11-22 13:04:23 +00:00
Mathias Vorreiter Pedersen
f308be7382 C++: Restore the missing flow. This has a couple of side-effects: First, it gives us some new good flow (yay). Second, it causes some duplication of results that uses 'argv' as a taint source. The duplication isn't very bad, though. And since it is only for paths that start at 'argv', I think we can live with it for now. 2021-11-22 13:04:07 +00:00
Mathias Vorreiter Pedersen
74221f4aba Merge pull request #7209 from geoffw0/experimental-tests
C++: Move experimental test.
2021-11-22 13:01:52 +00:00
Harry Maclean
6f22867af9 Merge pull request #7015 from github/hmac/ssrf
Ruby: Add Server-Side Request Forgery query
2021-11-22 12:41:39 +00:00
CodeQL CI
ddeb700fd6 Merge pull request #7207 from github/asgerf/document-template-language-extensions
Approved by esbena
2021-11-22 04:16:19 -08:00
Tom Hvitved
fc64faefcf Ruby: Restrict use-use flow 2021-11-22 13:05:17 +01:00
Erik Krogh Kristensen
e9df860431 refactor implementation to make Label implementations private 2021-11-22 12:17:19 +01:00
Geoffrey White
6f2b528a32 C++: Move experimental test. 2021-11-22 11:02:06 +00:00
Asger F
8322a44379 JS: Mention .hbs, .ejs, and .njk file extensions
Also fixes a typo `.xhm` -> `.xhtm`
2021-11-22 11:53:55 +01:00
Rasmus Wriedt Larsen
f09f1c4c50 Python: Minor refactor in PoorMansFunctionResolution 2021-11-22 11:11:29 +01:00
Tom Hvitved
39e3254fe0 Merge pull request #7182 from hvitved/csharp/self-assignment-bad-magic
C#: Fix bad magic `Element::fromSource` in context of `SelfAssignment.ql`
2021-11-22 10:57:48 +01:00
AlonaHlobina
0de6511dff Update query-metadata-style-guide.md 2021-11-22 10:17:57 +01:00
Erik Krogh Kristensen
6060f2e3e3 remove unused alias edge 2021-11-22 09:03:40 +01:00
Erik Krogh Kristensen
c369b28a2a optimizations in global data flow 2021-11-22 09:03:40 +01:00
Erik Krogh Kristensen
f39872e649 cache more predicates 2021-11-22 09:03:36 +01:00
Erik Krogh Kristensen
089d030bc2 make ApiLabel into a IPA type, and cache the public API of ApiGraphs 2021-11-22 09:03:33 +01:00
Erik Krogh Kristensen
9f08acab7e Merge pull request #7170 from erik-krogh/qldocStyle
Ruby: use A/An/The to start qlDoc for classes
2021-11-19 17:34:35 +01:00
Nick Rolfe
df6ba43cca Python: treat \A, \Z, \b, \B as special chars, not escapes 2021-11-19 15:49:53 +00:00
Anders Schack-Mulligen
344f7bca5b Merge pull request #7187 from aschackmull/java/dont-clear-in-summary-store
Java: Don't clear content in store steps in summaries.
2021-11-19 16:12:37 +01:00
Harry Maclean
06000781e9 Ruby: Document PairCfgNode::getKey/getValue 2021-11-19 14:54:06 +00:00
Nick Rolfe
f63c768d9f Ruby: parse \G, \b, and \B anchors as special characters, not escapes 2021-11-19 14:20:51 +00:00
Anders Schack-Mulligen
fc43220864 Java: bugfix 2021-11-19 15:01:29 +01:00
ihsinme
6d27585b92 Update FindIncorrectlyUsedExceptions.ql 2021-11-19 16:59:00 +03:00
Anders Schack-Mulligen
2b1f34ed9b Java: Don't clear content in store steps in summaries. 2021-11-19 14:22:28 +01:00
ihsinme
418adb824c Update FindIncorrectlyUsedExceptions.ql 2021-11-19 16:04:04 +03:00
Henry Mercer
8ba864e897 JS: Rename the available ML models external predicate 2021-11-19 12:56:03 +00:00
Tom Hvitved
47fd64fc44 Merge pull request #7130 from hvitved/cfg/dead-end-consistency
Shared CFG: Add "dead end" consistency query
2021-11-19 13:49:53 +01:00
Tom Hvitved
2b2ff7717e Merge pull request #7179 from hvitved/ruby/shared-ssa-consistency
Ruby: Move SSA consistency queries into shared SSA library
2021-11-19 13:49:25 +01:00
Erik Krogh Kristensen
75586b0cf6 Apply suggestions from code review
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2021-11-19 13:23:01 +01:00
Tom Hvitved
a393bff6cb C#: Fix bad magic Element::getLocation in context of SelfAssignment.ql 2021-11-19 12:44:07 +01:00
Harry Maclean
90a9688310 Ruby: update CFG fixture 2021-11-19 11:31:14 +00:00
Benjamin Muskalla
cd39d15b40 Simplify diagnostic query 2021-11-19 12:28:24 +01:00
Harry Maclean
8fc7e4be43 Ruby: Increase precision of SSRF query 2021-11-19 11:28:09 +00:00
Harry Maclean
c297a68acf Model more of the RestClient API
We now handle this form:

    RestClient::Request.execute(url: "http://example.com")
2021-11-19 11:28:09 +00:00
Harry Maclean
e2ef780c55 Add base_uri note to HTTParty modelling 2021-11-19 11:28:09 +00:00
Harry Maclean
38ff584307 Model more Faraday behaviour
You can instantiate a Faraday connection by passing a URL as an keyword
argument:

    conn = Faraday.new(url: "http://example.com")
2021-11-19 11:28:09 +00:00
Harry Maclean
f933d24031 Fix comment 2021-11-19 11:28:09 +00:00
Harry Maclean
70efadac77 Add change note for Ruby SSRF query 2021-11-19 11:28:09 +00:00
Harry Maclean
e87a4531d8 Remove redundant imports 2021-11-19 11:28:08 +00:00
Harry Maclean
ac20eafecc Add qhelp for Ruby SSRF 2021-11-19 11:28:08 +00:00
Harry Maclean
2bba31eb02 Update metadata of Ruby SSRF query 2021-11-19 11:28:08 +00:00
Harry Maclean
dc464879a2 Add a query for server-side request forgery 2021-11-19 11:28:08 +00:00
Harry Maclean
cd33e4d394 Make string interpolation sanitizer reusable 2021-11-19 11:28:08 +00:00
Harry Maclean
b6ce37b241 Add getURL to HTTP::Client::Request
This member predicate gets dataflow nodes which contribute to the URL of
the request.

Also consolidate the identical tests for each HTTP client.
2021-11-19 11:28:08 +00:00
Harry Maclean
8fd8c9b04d Fix CallExprCfgNode.getKeywordArgument
This predicate now produces results.
2021-11-19 11:28:08 +00:00
Harry Maclean
0caea17118 Add a test for CallCfgNodes
This test shows that `CallCfgNode.getKeywordArgument(string keyword)`
doesn't return any results.
2021-11-19 11:28:07 +00:00
Tom Hvitved
34feafd4fa C#: Do not pass in TSourceVariable IPA type into shared SSA library 2021-11-19 11:53:25 +01:00
Anders Schack-Mulligen
1f3f7e9ccc Merge pull request #7169 from erik-krogh/useMatches
use matches instead of regexpMatch/prefix/suffix
2021-11-19 11:42:47 +01:00
Tom Hvitved
4068cc9c3a Shared SSA: Sync files 2021-11-19 11:31:28 +01:00
Tom Hvitved
bc80c9b013 Ruby: Move SSA consistency queries into shared SSA library 2021-11-19 11:31:28 +01:00
Benjamin Muskalla
fb9b16325d Add diagnostic query for framework coverage 2021-11-19 10:30:59 +01:00
Tom Hvitved
fd0e318eb1 C#: Document inconsistency in one test 2021-11-19 09:43:51 +01:00
Tom Hvitved
923ca134e8 Shared CFG: Add "dead end" consistency query 2021-11-19 09:14:38 +01:00
ihsinme
fd73f4094f Update FindIncorrectlyUsedExceptions.ql 2021-11-19 10:54:02 +03:00
luchua-bc
b6a6ed5ba3 Add a recommendation category query for local user input and check Apache file upload 2021-11-19 04:23:19 +00:00
Erik Krogh Kristensen
62730e7a4b Merge pull request #7174 from erik-krogh/fixCSharpImport
C#: move Linq/Helpers.qll to the lib folder
2021-11-18 19:40:53 +01:00
Tom Hvitved
a4538de3a3 Shared CFG: Rename TNode to TCfgNode
This is in order to avoid name clash with the often so-named IPA type for data-
flow nodes. The name clash is not problematic because they are both in scope,
but because (cached) IPA types with overlapping names are known to sometimes
result in re-evaluation of cached stages, when one of the IPA types gets an
internal `#2` suffix in one query run, and the other IPA type gets the suffix
in another run.
2021-11-18 19:15:36 +01:00
Tom Hvitved
2f7250a0b3 Merge pull request #7160 from hvitved/csharp/cfg/static-scope
C#: Extend `(Annotated)ExitNode` to also cover static fields
2021-11-18 19:15:06 +01:00
Erik Krogh Kristensen
63ecae5426 update imports 2021-11-18 17:31:17 +01:00
Erik Krogh Kristensen
2d78cce7a5 move Linq/Helpers to the lib folder 2021-11-18 16:59:34 +01:00
Erik Krogh Kristensen
ee858d840e get ReDoSUtil in sync for ruby 2021-11-18 16:49:34 +01:00
Tom Hvitved
2218516685 Ruby: Remove CP in EnsureSplitImpl::exit/3 2021-11-18 16:05:09 +01:00
Erik Krogh Kristensen
af55f172ae use A/An/The to start qlDoc for classes 2021-11-18 15:42:45 +01:00
Erik Krogh Kristensen
011fc20963 use matches instead of regexpMatch 2021-11-18 15:41:25 +01:00
Alex Ford
1ec935dee6 Ruby: make documentation of IOReader and FileReader less ambiguous 2021-11-18 14:35:44 +00:00
Alex Ford
bd940712de Update ruby/ql/lib/codeql/ruby/frameworks/Files.qll
Co-authored-by: Harry Maclean <hmac@github.com>
2021-11-18 14:18:39 +00:00
Alex Ford
9a74f18ac5 Ruby: take File::try_convert as a potential file instance instantiation 2021-11-17 23:19:13 +00:00
Alex Ford
ce004e9c1e Ruby: don't interpret File#try_convert as a method that reads from a file/IO 2021-11-17 23:01:19 +00:00
Alex Ford
12a3251649 Ruby: extend FileSystemReadAccess and restructure some Files.qll classes 2021-11-17 23:01:18 +00:00
Tom Hvitved
a89be2e3f8 C#: Extend (Annotated)ExitNode to also cover static fields 2021-11-17 20:50:38 +01:00
Tom Hvitved
de72a765e0 Ruby: Update expected CFG test output (reordering) 2021-11-17 13:44:55 +01:00
Tom Hvitved
9ff63b00d6 Ruby: Remove CFG dependency from AST stage
Commit 028ef6f27f had the unintended side-effect
that the AST and CFG stages got merged, because the AST stage's `isCapturedAccess`
now depends on `getCfgScopeImpl`, which belongs to the CFG stage.

The fix is to remove `getCfgScopeImpl` from the CFG stage, and instead let it
be part of the AST stage.
2021-11-17 13:15:55 +01:00
Tom Hvitved
08c778241d Ruby: Adopt to changes after rebase 2021-11-17 09:17:32 +01:00
Tom Hvitved
413375992d Ruby: Flatten nested statements inside desugared for loops 2021-11-17 09:05:37 +01:00
Tom Hvitved
9125b85ff0 Ruby: Add missing QL doc 2021-11-17 09:05:37 +01:00
Tom Hvitved
92453bd2c5 Ruby: Rewrite break_ensure.rb CFG test to use while loops instead of for loops 2021-11-17 09:05:37 +01:00
Tom Hvitved
945bb7459a Ruby: Update expected test output 2021-11-17 09:05:37 +01:00
Tom Hvitved
a62ad5000b Ruby: Make isCapturedAccess work with synthesized scopes 2021-11-17 09:05:37 +01:00
Tom Hvitved
135ee0d0c1 Ruby: Add implicit writes for synthesized parameters 2021-11-17 09:05:37 +01:00
Tom Hvitved
028ef6f27f Ruby: Handle synthesized scopes 2021-11-17 09:05:37 +01:00
Tom Hvitved
48e6bdb117 Ruby: Remove EmptinessCompletion 2021-11-17 09:05:36 +01:00
Tom Hvitved
db6f843641 Ruby: Hide SynthBlock from the public API 2021-11-17 09:05:36 +01:00
Alex Ford
8603609698 Update test output to account for for-loop -> each desugaring 2021-11-17 09:05:36 +01:00
Alex Ford
e468434b82 ruby: drop special handling of for-in loops in the CFG 2021-11-17 09:05:33 +01:00
Alex Ford
ddfcfc9b67 Desugar for loops as each calls 2021-11-17 09:04:29 +01:00
Alex Ford
f6d99dc00d Define getBlockImpl for synthesized method calls 2021-11-17 09:04:29 +01:00
Alex Ford
a743067dc8 Support synthesis of blocks (without a new variable scope) 2021-11-17 09:04:29 +01:00
Alex Ford
04df56d1c0 Support synthesis of SimpleParameters 2021-11-17 09:04:29 +01:00
Rasmus Wriedt Larsen
98e6fc8a88 Python/Ruby: Remove owasp tags
These are no longer correct, since the A1 category changed from 2017 to
2021, see https://owasp.org/Top10/#whats-changed-in-the-top-10-for-2021

Since only a very few queries had these tags, I think we're much better
off having them removed.
2021-11-16 12:03:50 +01:00
Rasmus Wriedt Larsen
a980f26fda Python: Model os.stat (and friends) 2021-11-16 10:45:32 +01:00
Rasmus Wriedt Larsen
9f4107d211 Python: Model posixpath, ntpath, and genericpath modules 2021-11-16 10:45:14 +01:00
Rasmus Wriedt Larsen
9e097f5430 Python: Improve PoorMansFunctionResolution 2021-11-15 13:40:19 +01:00
Rasmus Wriedt Larsen
0d4cb1e6ce Python: Add test of PoorMansFunctionResolution 2021-11-15 13:34:39 +01:00
Rasmus Wriedt Larsen
6eb4525ab2 Python: Model wsgiref.simple_server applications 2021-11-15 13:34:39 +01:00
Rasmus Wriedt Larsen
e812029c03 Python: Add test for wsgiref.simple_server 2021-11-15 13:34:38 +01:00
Erik Krogh Kristensen
f0c5a80d1a apply the explicit this patch to new code 2021-11-13 21:03:54 +01:00
Erik Krogh Kristensen
0ff36cd083 Merge branch 'main' into explicit-this 2021-11-13 21:01:25 +01:00
Rasmus Wriedt Larsen
b11d11c0c9 Python: Add change-note 2021-11-12 14:27:01 +01:00
Nick Rolfe
9034d74663 Ruby: add file-level qldoc 2021-11-12 11:12:27 +00:00
Mathias Vorreiter Pedersen
dbcd4d6d5d C++: Remove 'ReferenceToInstruction' from the list of instructions we interpret as a load. This makes use lose a bunch of flow, and we'll restore this flow in the next commit. 2021-11-11 10:38:52 +00:00
Rasmus Wriedt Larsen
77099fe9d0 Python: Always use @id py/
The two queries in CWE-020 are used for manual evaluation (is my
understanding), and the two IDE queries should work based on their tags,
and not on the query-id.
2021-11-10 10:40:17 +01:00
Rasmus Wriedt Larsen
9710aeecbf Python/C#: Add CWE-1333 to redos queries
As is already done in JS and Ruby.
2021-11-09 16:10:38 +01:00
Alex Ford
556cdbaa21 ruby: QL format 2021-11-09 14:09:11 +00:00
Alex Ford
37775407a9 ruby: drop a redundant bit of documentation 2021-11-09 14:07:00 +00:00
Alex Ford
340897f262 ruby: drop unnecessary variable 2021-11-09 14:06:21 +00:00
Alex Ford
a23750a9c7 ruby: inline some predicates 2021-11-09 14:06:21 +00:00
Alex Ford
c65d1d9a50 ruby: CSRFProtectionDisabled.qhelp fixes
Co-authored-by: Harry Maclean <hmac@github.com>
2021-11-09 14:05:41 +00:00
Mathias Vorreiter Pedersen
10bca3544c C++: Change 'annotate_path_to_sink' so that you now annotate a ir-path with the previous node (instead of its source). This gives a better overview of the path. 2021-11-09 13:49:12 +00:00
Alex Ford
5f78bbbf52 add missing documentation 2021-11-04 21:07:54 +00:00
Alex Ford
543bd28b03 add a change note for rb/csrf-protection-disabled 2021-11-04 20:14:54 +00:00
Alex Ford
d324f9397c qhelp for rb/csrf-protection-disabled 2021-11-04 19:56:56 +00:00
Alex Ford
25da904314 test cases for rb/csrf-protection-disabled 2021-11-04 19:56:56 +00:00
Alex Ford
4666024419 model some ways to configure Rails 2021-11-04 19:56:56 +00:00
Alex Ford
91f99ed2a1 model skip_forgery_protection calls in ActionController classes 2021-11-04 19:56:56 +00:00
Alex Ford
fad7e9489b Add a query to detect instances of CSRF protection being disabled 2021-11-04 19:56:55 +00:00
Alex Ford
8a412dc5fd Add CSRFProtectionSetting concept 2021-11-04 18:18:29 +00:00
Rasmus Wriedt Larsen
84b38b6c32 Python: Add test with custom django json response (FP) 2021-11-03 14:17:08 +01:00
Nick Rolfe
dd17271ec8 Merge remote-tracking branch 'origin/main' into nickrolfe/regex_injection 2021-11-03 11:55:42 +00:00
Erik Krogh Kristensen
db40ccae81 add explicit this to all member calls 2021-11-01 09:51:15 +01:00
Nick Rolfe
fed0a06353 Ruby: add change note for rb/regexp-injection 2021-10-29 11:28:34 +01:00
Rasmus Lerchedahl Petersen
7201b3e116 Python: add changenote 2021-10-28 14:48:48 +02:00
Rasmus Lerchedahl Petersen
8536f5f5a2 Python: remember to update refs... 2021-10-28 14:32:53 +02:00
Nick Rolfe
bd92403b42 Ruby: fix qhelp 2021-10-28 10:42:56 +01:00
Nick Rolfe
11154a9409 Ruby: add regex injection query 2021-10-27 15:58:12 +01:00
Rasmus Lerchedahl Petersen
fed6a97eb8 Python: Promote ReDoS queries 2021-10-27 11:03:57 +02:00
Tony Torralba
9d50511ea4 Fix stubs 2021-10-18 09:27:53 +02:00
Tony Torralba
5deb996b33 Merge branch 'main' into atorralba/android_slice_models 2021-10-18 08:41:48 +02:00
Tony Torralba
91efb61e97 Use synthetic fields to improve taint precision 2021-10-07 17:03:08 +02:00
Tony Torralba
0325c07bd9 Reorganize fluent models 2021-10-07 17:03:07 +02:00
Tony Torralba
ffa77f0a76 Fix QLDoc 2021-10-07 17:03:07 +02:00
Tony Torralba
588dedc265 Add stubs 2021-10-07 17:03:05 +02:00
Tony Torralba
1a04ad98bc Add Android Slice models 2021-10-07 17:01:16 +02:00
luchua-bc
378db7de87 Remove local user input and use fluent model 2021-09-27 17:33:04 +00:00
luchua-bc
5264936fc3 Correct the run method and add Math.min check 2021-09-24 21:00:53 +00:00
luchua-bc
272e4f6cf9 Update the query 2021-09-24 01:48:11 +00:00
luchua-bc
2dc38aee54 Update qldoc 2021-09-23 20:31:24 +00:00
luchua-bc
8170f01b66 Query to detect uncontrolled thread resource consumption 2021-09-20 02:12:47 +00:00
1024 changed files with 68371 additions and 27612 deletions

View File

@@ -1,11 +1,23 @@
{ "provide": [ "ruby/.codeqlmanifest.json",
"*/ql/src/qlpack.yml",
"*/ql/lib/qlpack.yml",
"*/ql/test/qlpack.yml",
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
"*/ql/examples/qlpack.yml",
"*/upgrades/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
"misc/legacy-support/*/qlpack.yml",
"misc/suite-helpers/qlpack.yml" ] }
{
"provide": [
"*/ql/src/qlpack.yml",
"*/ql/lib/qlpack.yml",
"*/ql/test/qlpack.yml",
"*/ql/examples/qlpack.yml",
"*/upgrades/qlpack.yml",
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
"misc/legacy-support/*/qlpack.yml",
"misc/suite-helpers/qlpack.yml",
"ruby/extractor-pack/codeql-extractor.yml",
"ruby/ql/consistency-queries/qlpack.yml"
],
"versionPolicies": {
"default": {
"requireChangeNotes": true,
"committedPrereleaseSuffix": "dev",
"committedVersion": "nextPatchRelease"
}
}
}

View File

@@ -24,7 +24,7 @@ jobs:
strategy:
fail-fast: false
matrix:
repo: [rails/rails, discourse/discourse, spree/spree]
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@@ -41,7 +41,7 @@ jobs:
- name: Create database
run: |
codeql database create \
--search-path "${{ github.workspace }}/ruby" \
--search-path "${{ github.workspace }}/ruby/extractor-pack" \
--threads 4 \
--language ruby --source-root "${{ github.workspace }}/repo" \
"${{ runner.temp }}/database"

View File

@@ -32,14 +32,14 @@ jobs:
- uses: ./ruby/actions/create-extractor-pack
- name: Run QL tests
run: |
codeql test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ruby" --additional-packs "${{ github.workspace }}" --consistency-queries ql/consistency-queries ql/test
codeql test run --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check QL formatting
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
- name: Check QL compilation
run: |
codeql query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ruby" --additional-packs "${{ github.workspace }}" "ql/src" "ql/examples"
codeql query compile --check-only --threads=4 --warnings=error "ql/src" "ql/examples"
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check DB upgrade scripts

View File

@@ -1,51 +0,0 @@
# benjamin-buttons.md
This file describes the changes that have been applied to
the library to make it behave as if it was younger.
## TaintedPath.ql
Sinks added between 2020-01-01 and 2020-10-06 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
Sinks added between 2018-08-02 and 2020-01-01 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+pathinjection
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+tainted-path
Sinks from the "graceful-fs" and "fs-extra" (added before the open-sourcing squash).
## Xss.ql
Sinks added between 2020-01-01 and 2020-10-06 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
- recursive type tracking for `jQuery::dollar`, `DOM::domValueRef`.
## SqlInjection.ql
Sinks added between 2020-01-01 and 2020-10-06 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-089
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
Sinks added between 2018-08-02 and 2020-01-01 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-089
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sql
TypeTracking in SQL.qll (added before the open-sourcing squash)
The model of `mssql` and `sequelize` (added before the open-sourcing squash)
## PseudoProperties
Pseudo-properties (`$name$`) used in type-tracking and global dataflow configurations have been disabled.
Found by searching for `"\$.*\$"`.

View File

@@ -460,9 +460,10 @@
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll"
],
"ReDoS Util Python/JS": [
"ReDoS Util Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll",
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll"
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll"
],
"ReDoS Exponential Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* A new query `cpp/certificate-not-checked` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* A new query `cpp/certificate-result-conflation` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.

9
cpp/ql/lib/CHANGELOG.md Normal file
View File

@@ -0,0 +1,9 @@
## 0.0.5
## 0.0.4
### New Features
* The QL library `semmle.code.cpp.commons.Exclusions` now contains a predicate
`isFromSystemMacroDefinition` for identifying code that originates from a
macro outside the project being analyzed.

View File

@@ -0,0 +1,7 @@
## 0.0.4
### New Features
* The QL library `semmle.code.cpp.commons.Exclusions` now contains a predicate
`isFromSystemMacroDefinition` for identifying code that originates from a
macro outside the project being analyzed.

View File

@@ -0,0 +1 @@
## 0.0.5

View File

@@ -0,0 +1,2 @@
---
lastReleaseVersion: 0.0.5

View File

@@ -1,7 +1,8 @@
name: codeql/cpp-all
version: 0.0.2
version: 0.0.5
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
library: true
dependencies:
codeql/cpp-upgrades: 0.0.2
codeql/cpp-upgrades: 0.0.3

View File

@@ -626,9 +626,9 @@ library class ExprEvaluator extends int {
// All assignments must have the same int value
result =
unique(Expr value |
value = v.getAnAssignedValue() and not ignoreVariableAssignment(e, v, value)
value = v.getAnAssignedValue() and not this.ignoreVariableAssignment(e, v, value)
|
getValueInternalNonSubExpr(value)
this.getValueInternalNonSubExpr(value)
)
)
}

View File

@@ -1,4 +1,6 @@
private import cpp
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.dataflow.internal.DataFlowUtil
/**
* Gets a function that might be called by `call`.
@@ -63,3 +65,17 @@ predicate mayBenefitFromCallContext(Call call, Function f) { none() }
* restricted to those `call`s for which a context might make a difference.
*/
Function viableImplInCallContext(Call call, Call ctx) { none() }
/** A parameter position represented by an integer. */
class ParameterPosition extends int {
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
}
/** An argument position represented by an integer. */
class ArgumentPosition extends int {
ArgumentPosition() { any(ArgumentNode a).argumentOf(_, this) }
}
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
pragma[inline]
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }

View File

@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
private class ParamNodeEx extends NodeEx {
ParamNodeEx() { this.asNode() instanceof ParamNode }
predicate isParameterOf(DataFlowCallable c, int i) {
this.asNode().(ParamNode).isParameterOf(c, i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.asNode().(ParamNode).isParameterOf(c, pos)
}
int getPosition() { this.isParameterOf(_, result) }
ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
@@ -289,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -307,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -320,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -342,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -363,10 +372,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -380,16 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -402,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -451,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -547,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -773,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1009,6 +1012,9 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1017,14 +1023,23 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1037,6 +1052,13 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1107,7 +1129,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1142,9 +1164,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1159,9 +1180,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1171,10 +1191,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1188,7 +1206,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1230,6 +1248,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1306,7 +1329,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1341,9 +1364,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1353,9 +1375,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1365,9 +1386,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1427,7 +1447,7 @@ private module Stage2 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -1707,12 +1727,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1837,9 +1859,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1854,9 +1875,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1866,10 +1886,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1925,6 +1943,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2001,7 +2024,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2036,9 +2059,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2048,9 +2070,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2060,9 +2081,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2122,7 +2142,7 @@ private module Stage3 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2473,12 +2493,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2603,9 +2625,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2620,9 +2641,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2632,10 +2652,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2691,6 +2709,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2767,7 +2790,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2802,9 +2825,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2814,9 +2836,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2826,9 +2847,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2888,7 +2908,7 @@ private module Stage4 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2972,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
int getParameterPos() { p.isParameterOf(_, result) }
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
@@ -3619,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
p.isParameterOf(callable, pos)
)
}
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, AccessPath ap, Configuration config
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
)
}
@@ -3666,9 +3687,9 @@ private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
(
sc = TSummaryCtxSome(p, ap)
or
@@ -3692,7 +3713,7 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret, int pos |
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -4421,24 +4442,25 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
PartialAccessPath ap, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
callable = resolveCall(call, outercc)
}
@@ -4447,9 +4469,9 @@ private module FlowExploration {
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(int i, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(ap)
|
@@ -4613,22 +4635,23 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
RevPartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeRev mid, ParamNodeEx p |
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
mid.getNodeEx() = p and
p.getPosition() = pos and
p.getPosition() = ppos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
@@ -4641,7 +4664,7 @@ private module FlowExploration {
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
exists(DataFlowCall call, ArgumentPosition pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.asNode().(ArgNode).argumentOf(call, pos)
)

View File

@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
private class ParamNodeEx extends NodeEx {
ParamNodeEx() { this.asNode() instanceof ParamNode }
predicate isParameterOf(DataFlowCallable c, int i) {
this.asNode().(ParamNode).isParameterOf(c, i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.asNode().(ParamNode).isParameterOf(c, pos)
}
int getPosition() { this.isParameterOf(_, result) }
ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
@@ -289,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -307,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -320,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -342,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -363,10 +372,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -380,16 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -402,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -451,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -547,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -773,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1009,6 +1012,9 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1017,14 +1023,23 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1037,6 +1052,13 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1107,7 +1129,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1142,9 +1164,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1159,9 +1180,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1171,10 +1191,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1188,7 +1206,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1230,6 +1248,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1306,7 +1329,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1341,9 +1364,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1353,9 +1375,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1365,9 +1386,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1427,7 +1447,7 @@ private module Stage2 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -1707,12 +1727,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1837,9 +1859,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1854,9 +1875,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1866,10 +1886,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1925,6 +1943,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2001,7 +2024,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2036,9 +2059,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2048,9 +2070,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2060,9 +2081,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2122,7 +2142,7 @@ private module Stage3 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2473,12 +2493,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2603,9 +2625,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2620,9 +2641,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2632,10 +2652,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2691,6 +2709,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2767,7 +2790,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2802,9 +2825,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2814,9 +2836,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2826,9 +2847,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2888,7 +2908,7 @@ private module Stage4 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2972,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
int getParameterPos() { p.isParameterOf(_, result) }
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
@@ -3619,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
p.isParameterOf(callable, pos)
)
}
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, AccessPath ap, Configuration config
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
)
}
@@ -3666,9 +3687,9 @@ private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
(
sc = TSummaryCtxSome(p, ap)
or
@@ -3692,7 +3713,7 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret, int pos |
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -4421,24 +4442,25 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
PartialAccessPath ap, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
callable = resolveCall(call, outercc)
}
@@ -4447,9 +4469,9 @@ private module FlowExploration {
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(int i, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(ap)
|
@@ -4613,22 +4635,23 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
RevPartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeRev mid, ParamNodeEx p |
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
mid.getNodeEx() = p and
p.getPosition() = pos and
p.getPosition() = ppos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
@@ -4641,7 +4664,7 @@ private module FlowExploration {
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
exists(DataFlowCall call, ArgumentPosition pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.asNode().(ArgNode).argumentOf(call, pos)
)

View File

@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
private class ParamNodeEx extends NodeEx {
ParamNodeEx() { this.asNode() instanceof ParamNode }
predicate isParameterOf(DataFlowCallable c, int i) {
this.asNode().(ParamNode).isParameterOf(c, i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.asNode().(ParamNode).isParameterOf(c, pos)
}
int getPosition() { this.isParameterOf(_, result) }
ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
@@ -289,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -307,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -320,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -342,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -363,10 +372,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -380,16 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -402,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -451,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -547,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -773,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1009,6 +1012,9 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1017,14 +1023,23 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1037,6 +1052,13 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1107,7 +1129,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1142,9 +1164,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1159,9 +1180,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1171,10 +1191,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1188,7 +1206,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1230,6 +1248,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1306,7 +1329,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1341,9 +1364,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1353,9 +1375,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1365,9 +1386,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1427,7 +1447,7 @@ private module Stage2 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -1707,12 +1727,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1837,9 +1859,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1854,9 +1875,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1866,10 +1886,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1925,6 +1943,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2001,7 +2024,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2036,9 +2059,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2048,9 +2070,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2060,9 +2081,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2122,7 +2142,7 @@ private module Stage3 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2473,12 +2493,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2603,9 +2625,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2620,9 +2641,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2632,10 +2652,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2691,6 +2709,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2767,7 +2790,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2802,9 +2825,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2814,9 +2836,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2826,9 +2847,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2888,7 +2908,7 @@ private module Stage4 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2972,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
int getParameterPos() { p.isParameterOf(_, result) }
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
@@ -3619,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
p.isParameterOf(callable, pos)
)
}
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, AccessPath ap, Configuration config
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
)
}
@@ -3666,9 +3687,9 @@ private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
(
sc = TSummaryCtxSome(p, ap)
or
@@ -3692,7 +3713,7 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret, int pos |
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -4421,24 +4442,25 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
PartialAccessPath ap, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
callable = resolveCall(call, outercc)
}
@@ -4447,9 +4469,9 @@ private module FlowExploration {
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(int i, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(ap)
|
@@ -4613,22 +4635,23 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
RevPartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeRev mid, ParamNodeEx p |
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
mid.getNodeEx() = p and
p.getPosition() = pos and
p.getPosition() = ppos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
@@ -4641,7 +4664,7 @@ private module FlowExploration {
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
exists(DataFlowCall call, ArgumentPosition pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.asNode().(ArgNode).argumentOf(call, pos)
)

View File

@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
private class ParamNodeEx extends NodeEx {
ParamNodeEx() { this.asNode() instanceof ParamNode }
predicate isParameterOf(DataFlowCallable c, int i) {
this.asNode().(ParamNode).isParameterOf(c, i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.asNode().(ParamNode).isParameterOf(c, pos)
}
int getPosition() { this.isParameterOf(_, result) }
ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
@@ -289,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -307,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -320,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -342,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -363,10 +372,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -380,16 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -402,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -451,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -547,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -773,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1009,6 +1012,9 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1017,14 +1023,23 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1037,6 +1052,13 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1107,7 +1129,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1142,9 +1164,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1159,9 +1180,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1171,10 +1191,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1188,7 +1206,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1230,6 +1248,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1306,7 +1329,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1341,9 +1364,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1353,9 +1375,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1365,9 +1386,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1427,7 +1447,7 @@ private module Stage2 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -1707,12 +1727,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1837,9 +1859,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1854,9 +1875,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1866,10 +1886,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1925,6 +1943,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2001,7 +2024,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2036,9 +2059,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2048,9 +2070,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2060,9 +2081,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2122,7 +2142,7 @@ private module Stage3 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2473,12 +2493,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2603,9 +2625,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2620,9 +2641,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2632,10 +2652,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2691,6 +2709,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2767,7 +2790,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2802,9 +2825,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2814,9 +2836,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2826,9 +2847,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2888,7 +2908,7 @@ private module Stage4 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2972,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
int getParameterPos() { p.isParameterOf(_, result) }
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
@@ -3619,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
p.isParameterOf(callable, pos)
)
}
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, AccessPath ap, Configuration config
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
)
}
@@ -3666,9 +3687,9 @@ private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
(
sc = TSummaryCtxSome(p, ap)
or
@@ -3692,7 +3713,7 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret, int pos |
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -4421,24 +4442,25 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
PartialAccessPath ap, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
callable = resolveCall(call, outercc)
}
@@ -4447,9 +4469,9 @@ private module FlowExploration {
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(int i, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(ap)
|
@@ -4613,22 +4635,23 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
RevPartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeRev mid, ParamNodeEx p |
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
mid.getNodeEx() = p and
p.getPosition() = pos and
p.getPosition() = ppos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
@@ -4641,7 +4664,7 @@ private module FlowExploration {
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
exists(DataFlowCall call, ArgumentPosition pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.asNode().(ArgNode).argumentOf(call, pos)
)

View File

@@ -62,6 +62,18 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
tupleLimit = 1000
}
/**
* Holds if `arg` is an argument of `call` with an argument position that matches
* parameter position `ppos`.
*/
pragma[noinline]
predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) {
exists(ArgumentPosition apos |
arg.argumentOf(call, apos) and
parameterMatch(ppos, apos)
)
}
/**
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
* currently excludes read-steps, store-steps, and flow-through.
@@ -71,25 +83,27 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/
private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i)
pragma[noinline]
private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
p.isParameterOf(viableCallable(call), ppos)
}
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i)
pragma[noinline]
private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), ppos)
}
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i)
exists(ParameterPosition ppos |
viableParamNonLambda(call, ppos, p) and
argumentPositionMatch(call, arg, ppos)
)
}
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamLambda(call, i, p) and
arg.argumentOf(call, i)
exists(ParameterPosition ppos |
viableParamLambda(call, ppos, p) and
argumentPositionMatch(call, arg, ppos)
)
}
@@ -322,7 +336,7 @@ private module Cached {
or
exists(ArgNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition())
)
}
@@ -330,7 +344,7 @@ private module Cached {
predicate returnNodeExt(Node n, ReturnKindExt k) {
k = TValueReturn(n.(ReturnNode).getKind())
or
exists(ParamNode p, int pos |
exists(ParamNode p, ParameterPosition pos |
parameterValueFlowsToPreUpdate(p, n) and
p.isParameterOf(_, pos) and
k = TParamUpdate(pos)
@@ -352,11 +366,13 @@ private module Cached {
}
cached
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
isParameterNode(p, c, pos)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNode).argumentOf(call, pos)
predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) {
isArgumentNode(n, call, pos)
}
/**
@@ -374,12 +390,12 @@ private module Cached {
}
/**
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
* The instance parameter is considered to have index `-1`.
* Holds if `p` is the parameter of a viable dispatch target of `call`,
* and `p` has position `ppos`.
*/
pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i)
private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
p.isParameterOf(viableCallableExt(call), ppos)
}
/**
@@ -388,9 +404,9 @@ private module Cached {
*/
cached
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParam(call, i, p) and
arg.argumentOf(call, i) and
exists(ParameterPosition ppos |
viableParam(call, ppos, p) and
argumentPositionMatch(call, arg, ppos) and
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
)
}
@@ -862,7 +878,7 @@ private module Cached {
cached
newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached
newtype TBooleanOption =
@@ -1054,9 +1070,9 @@ class ParamNode extends Node {
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
* position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) }
}
/** A data-flow node that represents a call argument. */
@@ -1064,7 +1080,9 @@ class ArgNode extends Node {
ArgNode() { argumentNode(this, _, _) }
/** Holds if this argument occurs at the given position in the given call. */
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
argumentNode(this, call, pos)
}
}
/**
@@ -1110,11 +1128,14 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
}
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
private int pos;
private ParameterPosition pos;
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
int getPosition() { result = pos }
ParameterPosition getPosition() { result = pos }
pragma[nomagic]
ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) }
override string toString() { result = "param update " + pos }
}

View File

@@ -9,6 +9,19 @@ private import tainttracking1.TaintTrackingParameter::Private
private import tainttracking1.TaintTrackingParameter::Public
module Consistency {
private newtype TConsistencyConfiguration = MkConsistencyConfiguration()
/** A class for configuring the consistency queries. */
class ConsistencyConfiguration extends TConsistencyConfiguration {
string toString() { none() }
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
predicate postWithInFlowExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
}
private class RelevantNode extends Node {
RelevantNode() {
this instanceof ArgumentNode or
@@ -164,7 +177,7 @@ module Consistency {
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
not hasPost(n) and
not isImmutableOrUnobservable(n) and
not any(ConsistencyConfiguration c).argHasPostUpdateExclude(n) and
msg = "ArgumentNode is missing PostUpdateNode."
}
@@ -177,6 +190,7 @@ module Consistency {
isPostUpdateNode(n) and
not clearsContent(n, _) and
simpleLocalFlowStep(_, n) and
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
msg = "PostUpdateNode should not be the target of local flow."
}
}

View File

@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
private class ParamNodeEx extends NodeEx {
ParamNodeEx() { this.asNode() instanceof ParamNode }
predicate isParameterOf(DataFlowCallable c, int i) {
this.asNode().(ParamNode).isParameterOf(c, i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.asNode().(ParamNode).isParameterOf(c, pos)
}
int getPosition() { this.isParameterOf(_, result) }
ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
@@ -289,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -307,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -320,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -342,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -363,10 +372,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -380,16 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -402,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -451,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -547,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -773,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1009,6 +1012,9 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1017,14 +1023,23 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1037,6 +1052,13 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1107,7 +1129,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1142,9 +1164,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1159,9 +1180,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1171,10 +1191,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1188,7 +1206,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1230,6 +1248,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1306,7 +1329,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1341,9 +1364,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1353,9 +1375,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1365,9 +1386,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1427,7 +1447,7 @@ private module Stage2 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -1707,12 +1727,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1837,9 +1859,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1854,9 +1875,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1866,10 +1886,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1925,6 +1943,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2001,7 +2024,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2036,9 +2059,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2048,9 +2070,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2060,9 +2081,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2122,7 +2142,7 @@ private module Stage3 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2473,12 +2493,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2603,9 +2625,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2620,9 +2641,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2632,10 +2652,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2691,6 +2709,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2767,7 +2790,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2802,9 +2825,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2814,9 +2836,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2826,9 +2847,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2888,7 +2908,7 @@ private module Stage4 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2972,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
int getParameterPos() { p.isParameterOf(_, result) }
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
@@ -3619,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
p.isParameterOf(callable, pos)
)
}
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, AccessPath ap, Configuration config
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
)
}
@@ -3666,9 +3687,9 @@ private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
(
sc = TSummaryCtxSome(p, ap)
or
@@ -3692,7 +3713,7 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret, int pos |
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -4421,24 +4442,25 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
PartialAccessPath ap, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
callable = resolveCall(call, outercc)
}
@@ -4447,9 +4469,9 @@ private module FlowExploration {
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(int i, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(ap)
|
@@ -4613,22 +4635,23 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
RevPartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeRev mid, ParamNodeEx p |
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
mid.getNodeEx() = p and
p.getPosition() = pos and
p.getPosition() = ppos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
@@ -4641,7 +4664,7 @@ private module FlowExploration {
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
exists(DataFlowCall call, ArgumentPosition pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.asNode().(ArgNode).argumentOf(call, pos)
)

View File

@@ -2,12 +2,20 @@ private import cpp
private import DataFlowUtil
private import DataFlowDispatch
private import FlowVar
private import DataFlowImplConsistency
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
p.isParameterOf(c, pos)
}
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
arg.argumentOf(c, pos)
}
/** Gets the instance argument of a non-static call. */
private Node getInstanceArgument(Call call) {
@@ -259,27 +267,6 @@ class Unit extends TUnit {
string toString() { result = "unit" }
}
/**
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
* modified or its modification cannot be observed, for example if it is a
* freshly created object that is not saved in a variable.
*
* This predicate is only used for consistency checks.
*/
predicate isImmutableOrUnobservable(Node n) {
// Is the null pointer (or something that's not really a pointer)
exists(n.asExpr().getValue())
or
// Isn't a pointer or is a pointer to const
forall(DerivedType dt | dt = n.asExpr().getActualType() |
dt.getBaseType().isConst()
or
dt.getBaseType() instanceof RoutineType
)
// The above list of cases isn't exhaustive, but it narrows down the
// consistency alerts enough that most of them are interesting.
}
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { none() }
@@ -302,3 +289,19 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
override predicate argHasPostUpdateExclude(ArgumentNode n) {
// Is the null pointer (or something that's not really a pointer)
exists(n.asExpr().getValue())
or
// Isn't a pointer or is a pointer to const
forall(DerivedType dt | dt = n.asExpr().getActualType() |
dt.getBaseType().isConst()
or
dt.getBaseType() instanceof RoutineType
)
// The above list of cases isn't exhaustive, but it narrows down the
// consistency alerts enough that most of them are interesting.
}
}

View File

@@ -484,8 +484,9 @@ module TaintedWithPath {
/** Gets the element that `pathNode` wraps, if any. */
Element getElementFromPathNode(PathNode pathNode) {
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
result = node.asExpr() or
result = node.asParameter()
result = node.asInstruction().getAST()
or
result = node.asOperand().getDef().getAST()
)
or
result = pathNode.(EndpointPathNode).inner()

View File

@@ -2,6 +2,7 @@ private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import DataFlowImplCommon as DataFlowImplCommon
/**
@@ -266,3 +267,17 @@ Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
result = ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
)
}
/** A parameter position represented by an integer. */
class ParameterPosition extends int {
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
}
/** An argument position represented by an integer. */
class ArgumentPosition extends int {
ArgumentPosition() { any(ArgumentNode a).argumentOf(_, this) }
}
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
pragma[inline]
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }

View File

@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
private class ParamNodeEx extends NodeEx {
ParamNodeEx() { this.asNode() instanceof ParamNode }
predicate isParameterOf(DataFlowCallable c, int i) {
this.asNode().(ParamNode).isParameterOf(c, i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.asNode().(ParamNode).isParameterOf(c, pos)
}
int getPosition() { this.isParameterOf(_, result) }
ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
@@ -289,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -307,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -320,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -342,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -363,10 +372,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -380,16 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -402,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -451,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -547,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -773,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1009,6 +1012,9 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1017,14 +1023,23 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1037,6 +1052,13 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1107,7 +1129,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1142,9 +1164,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1159,9 +1180,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1171,10 +1191,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1188,7 +1206,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1230,6 +1248,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1306,7 +1329,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1341,9 +1364,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1353,9 +1375,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1365,9 +1386,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1427,7 +1447,7 @@ private module Stage2 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -1707,12 +1727,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1837,9 +1859,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1854,9 +1875,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1866,10 +1886,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1925,6 +1943,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2001,7 +2024,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2036,9 +2059,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2048,9 +2070,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2060,9 +2081,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2122,7 +2142,7 @@ private module Stage3 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2473,12 +2493,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2603,9 +2625,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2620,9 +2641,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2632,10 +2652,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2691,6 +2709,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2767,7 +2790,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2802,9 +2825,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2814,9 +2836,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2826,9 +2847,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2888,7 +2908,7 @@ private module Stage4 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2972,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
int getParameterPos() { p.isParameterOf(_, result) }
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
@@ -3619,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
p.isParameterOf(callable, pos)
)
}
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, AccessPath ap, Configuration config
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
)
}
@@ -3666,9 +3687,9 @@ private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
(
sc = TSummaryCtxSome(p, ap)
or
@@ -3692,7 +3713,7 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret, int pos |
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -4421,24 +4442,25 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
PartialAccessPath ap, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
callable = resolveCall(call, outercc)
}
@@ -4447,9 +4469,9 @@ private module FlowExploration {
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(int i, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(ap)
|
@@ -4613,22 +4635,23 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
RevPartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeRev mid, ParamNodeEx p |
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
mid.getNodeEx() = p and
p.getPosition() = pos and
p.getPosition() = ppos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
@@ -4641,7 +4664,7 @@ private module FlowExploration {
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
exists(DataFlowCall call, ArgumentPosition pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.asNode().(ArgNode).argumentOf(call, pos)
)

View File

@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
private class ParamNodeEx extends NodeEx {
ParamNodeEx() { this.asNode() instanceof ParamNode }
predicate isParameterOf(DataFlowCallable c, int i) {
this.asNode().(ParamNode).isParameterOf(c, i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.asNode().(ParamNode).isParameterOf(c, pos)
}
int getPosition() { this.isParameterOf(_, result) }
ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
@@ -289,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -307,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -320,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -342,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -363,10 +372,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -380,16 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -402,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -451,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -547,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -773,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1009,6 +1012,9 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1017,14 +1023,23 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1037,6 +1052,13 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1107,7 +1129,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1142,9 +1164,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1159,9 +1180,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1171,10 +1191,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1188,7 +1206,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1230,6 +1248,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1306,7 +1329,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1341,9 +1364,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1353,9 +1375,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1365,9 +1386,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1427,7 +1447,7 @@ private module Stage2 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -1707,12 +1727,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1837,9 +1859,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1854,9 +1875,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1866,10 +1886,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1925,6 +1943,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2001,7 +2024,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2036,9 +2059,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2048,9 +2070,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2060,9 +2081,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2122,7 +2142,7 @@ private module Stage3 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2473,12 +2493,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2603,9 +2625,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2620,9 +2641,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2632,10 +2652,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2691,6 +2709,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2767,7 +2790,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2802,9 +2825,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2814,9 +2836,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2826,9 +2847,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2888,7 +2908,7 @@ private module Stage4 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2972,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
int getParameterPos() { p.isParameterOf(_, result) }
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
@@ -3619,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
p.isParameterOf(callable, pos)
)
}
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, AccessPath ap, Configuration config
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
)
}
@@ -3666,9 +3687,9 @@ private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
(
sc = TSummaryCtxSome(p, ap)
or
@@ -3692,7 +3713,7 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret, int pos |
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -4421,24 +4442,25 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
PartialAccessPath ap, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
callable = resolveCall(call, outercc)
}
@@ -4447,9 +4469,9 @@ private module FlowExploration {
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(int i, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(ap)
|
@@ -4613,22 +4635,23 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
RevPartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeRev mid, ParamNodeEx p |
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
mid.getNodeEx() = p and
p.getPosition() = pos and
p.getPosition() = ppos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
@@ -4641,7 +4664,7 @@ private module FlowExploration {
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
exists(DataFlowCall call, ArgumentPosition pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.asNode().(ArgNode).argumentOf(call, pos)
)

View File

@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
private class ParamNodeEx extends NodeEx {
ParamNodeEx() { this.asNode() instanceof ParamNode }
predicate isParameterOf(DataFlowCallable c, int i) {
this.asNode().(ParamNode).isParameterOf(c, i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.asNode().(ParamNode).isParameterOf(c, pos)
}
int getPosition() { this.isParameterOf(_, result) }
ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
@@ -289,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -307,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -320,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -342,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -363,10 +372,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -380,16 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -402,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -451,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -547,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -773,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1009,6 +1012,9 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1017,14 +1023,23 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1037,6 +1052,13 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1107,7 +1129,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1142,9 +1164,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1159,9 +1180,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1171,10 +1191,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1188,7 +1206,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1230,6 +1248,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1306,7 +1329,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1341,9 +1364,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1353,9 +1375,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1365,9 +1386,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1427,7 +1447,7 @@ private module Stage2 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -1707,12 +1727,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1837,9 +1859,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1854,9 +1875,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1866,10 +1886,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1925,6 +1943,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2001,7 +2024,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2036,9 +2059,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2048,9 +2070,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2060,9 +2081,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2122,7 +2142,7 @@ private module Stage3 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2473,12 +2493,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2603,9 +2625,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2620,9 +2641,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2632,10 +2652,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2691,6 +2709,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2767,7 +2790,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2802,9 +2825,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2814,9 +2836,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2826,9 +2847,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2888,7 +2908,7 @@ private module Stage4 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2972,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
int getParameterPos() { p.isParameterOf(_, result) }
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
@@ -3619,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
p.isParameterOf(callable, pos)
)
}
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, AccessPath ap, Configuration config
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
)
}
@@ -3666,9 +3687,9 @@ private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
(
sc = TSummaryCtxSome(p, ap)
or
@@ -3692,7 +3713,7 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret, int pos |
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -4421,24 +4442,25 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
PartialAccessPath ap, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
callable = resolveCall(call, outercc)
}
@@ -4447,9 +4469,9 @@ private module FlowExploration {
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(int i, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(ap)
|
@@ -4613,22 +4635,23 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
RevPartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeRev mid, ParamNodeEx p |
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
mid.getNodeEx() = p and
p.getPosition() = pos and
p.getPosition() = ppos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
@@ -4641,7 +4664,7 @@ private module FlowExploration {
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
exists(DataFlowCall call, ArgumentPosition pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.asNode().(ArgNode).argumentOf(call, pos)
)

View File

@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
private class ParamNodeEx extends NodeEx {
ParamNodeEx() { this.asNode() instanceof ParamNode }
predicate isParameterOf(DataFlowCallable c, int i) {
this.asNode().(ParamNode).isParameterOf(c, i)
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
this.asNode().(ParamNode).isParameterOf(c, pos)
}
int getPosition() { this.isParameterOf(_, result) }
ParameterPosition getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
@@ -289,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -307,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -320,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -342,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -363,10 +372,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -380,16 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -402,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -451,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -547,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -773,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1009,6 +1012,9 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1017,14 +1023,23 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1037,6 +1052,13 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1107,7 +1129,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1142,9 +1164,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1159,9 +1180,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1171,10 +1191,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1188,7 +1206,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1230,6 +1248,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1306,7 +1329,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1341,9 +1364,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1353,9 +1375,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1365,9 +1386,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1427,7 +1447,7 @@ private module Stage2 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -1707,12 +1727,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1837,9 +1859,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1854,9 +1875,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1866,10 +1886,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1925,6 +1943,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2001,7 +2024,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2036,9 +2059,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2048,9 +2070,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2060,9 +2081,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2122,7 +2142,7 @@ private module Stage3 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2473,12 +2493,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2603,9 +2625,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2620,9 +2641,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2632,10 +2652,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2691,6 +2709,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2767,7 +2790,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2802,9 +2825,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2814,9 +2836,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2826,9 +2847,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2888,7 +2908,7 @@ private module Stage4 {
}
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
@@ -2972,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
int getParameterPos() { p.isParameterOf(_, result) }
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
@@ -3619,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
p.isParameterOf(callable, pos)
)
}
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, AccessPath ap, Configuration config
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
)
}
@@ -3666,9 +3687,9 @@ private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
(
sc = TSummaryCtxSome(p, ap)
or
@@ -3692,7 +3713,7 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret, int pos |
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
mid.getNodeEx() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -4421,24 +4442,25 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
PartialAccessPath ap, Configuration config
) {
exists(ArgNode arg |
exists(ArgNode arg, ArgumentPosition apos |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
arg.argumentOf(call, apos) and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
callable = resolveCall(call, outercc)
}
@@ -4447,9 +4469,9 @@ private module FlowExploration {
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(int i, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
p.isParameterOf(callable, i) and
exists(ParameterPosition pos, DataFlowCallable callable |
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
p.isParameterOf(callable, pos) and
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(ap)
|
@@ -4613,22 +4635,23 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
RevPartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeRev mid, ParamNodeEx p |
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
mid.getNodeEx() = p and
p.getPosition() = pos and
p.getPosition() = ppos and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
config = mid.getConfiguration() and
parameterMatch(ppos, apos)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
@@ -4641,7 +4664,7 @@ private module FlowExploration {
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
exists(DataFlowCall call, ArgumentPosition pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.asNode().(ArgNode).argumentOf(call, pos)
)

View File

@@ -62,6 +62,18 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
tupleLimit = 1000
}
/**
* Holds if `arg` is an argument of `call` with an argument position that matches
* parameter position `ppos`.
*/
pragma[noinline]
predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) {
exists(ArgumentPosition apos |
arg.argumentOf(call, apos) and
parameterMatch(ppos, apos)
)
}
/**
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
* currently excludes read-steps, store-steps, and flow-through.
@@ -71,25 +83,27 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/
private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i)
pragma[noinline]
private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
p.isParameterOf(viableCallable(call), ppos)
}
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i)
pragma[noinline]
private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), ppos)
}
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i)
exists(ParameterPosition ppos |
viableParamNonLambda(call, ppos, p) and
argumentPositionMatch(call, arg, ppos)
)
}
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamLambda(call, i, p) and
arg.argumentOf(call, i)
exists(ParameterPosition ppos |
viableParamLambda(call, ppos, p) and
argumentPositionMatch(call, arg, ppos)
)
}
@@ -322,7 +336,7 @@ private module Cached {
or
exists(ArgNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition())
)
}
@@ -330,7 +344,7 @@ private module Cached {
predicate returnNodeExt(Node n, ReturnKindExt k) {
k = TValueReturn(n.(ReturnNode).getKind())
or
exists(ParamNode p, int pos |
exists(ParamNode p, ParameterPosition pos |
parameterValueFlowsToPreUpdate(p, n) and
p.isParameterOf(_, pos) and
k = TParamUpdate(pos)
@@ -352,11 +366,13 @@ private module Cached {
}
cached
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
isParameterNode(p, c, pos)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNode).argumentOf(call, pos)
predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) {
isArgumentNode(n, call, pos)
}
/**
@@ -374,12 +390,12 @@ private module Cached {
}
/**
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
* The instance parameter is considered to have index `-1`.
* Holds if `p` is the parameter of a viable dispatch target of `call`,
* and `p` has position `ppos`.
*/
pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i)
private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
p.isParameterOf(viableCallableExt(call), ppos)
}
/**
@@ -388,9 +404,9 @@ private module Cached {
*/
cached
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParam(call, i, p) and
arg.argumentOf(call, i) and
exists(ParameterPosition ppos |
viableParam(call, ppos, p) and
argumentPositionMatch(call, arg, ppos) and
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
)
}
@@ -862,7 +878,7 @@ private module Cached {
cached
newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached
newtype TBooleanOption =
@@ -1054,9 +1070,9 @@ class ParamNode extends Node {
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
* position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) }
}
/** A data-flow node that represents a call argument. */
@@ -1064,7 +1080,9 @@ class ArgNode extends Node {
ArgNode() { argumentNode(this, _, _) }
/** Holds if this argument occurs at the given position in the given call. */
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
argumentNode(this, call, pos)
}
}
/**
@@ -1110,11 +1128,14 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
}
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
private int pos;
private ParameterPosition pos;
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
int getPosition() { result = pos }
ParameterPosition getPosition() { result = pos }
pragma[nomagic]
ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) }
override string toString() { result = "param update " + pos }
}

View File

@@ -9,6 +9,19 @@ private import tainttracking1.TaintTrackingParameter::Private
private import tainttracking1.TaintTrackingParameter::Public
module Consistency {
private newtype TConsistencyConfiguration = MkConsistencyConfiguration()
/** A class for configuring the consistency queries. */
class ConsistencyConfiguration extends TConsistencyConfiguration {
string toString() { none() }
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
predicate postWithInFlowExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
}
private class RelevantNode extends Node {
RelevantNode() {
this instanceof ArgumentNode or
@@ -164,7 +177,7 @@ module Consistency {
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
not hasPost(n) and
not isImmutableOrUnobservable(n) and
not any(ConsistencyConfiguration c).argHasPostUpdateExclude(n) and
msg = "ArgumentNode is missing PostUpdateNode."
}
@@ -177,6 +190,7 @@ module Consistency {
isPostUpdateNode(n) and
not clearsContent(n, _) and
simpleLocalFlowStep(_, n) and
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
msg = "PostUpdateNode should not be the target of local flow."
}
}

View File

@@ -2,12 +2,20 @@ private import cpp
private import DataFlowUtil
private import semmle.code.cpp.ir.IR
private import DataFlowDispatch
private import DataFlowImplConsistency
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
p.isParameterOf(c, pos)
}
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
arg.argumentOf(c, pos)
}
/**
* A data flow node that occurs as the argument of a call and is passed as-is
@@ -285,21 +293,18 @@ class Unit extends TUnit {
string toString() { result = "unit" }
}
/**
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
* modified or its modification cannot be observed, for example if it is a
* freshly created object that is not saved in a variable.
*
* This predicate is only used for consistency checks.
*/
predicate isImmutableOrUnobservable(Node n) {
// The rules for whether an IR argument gets a post-update node are too
// complex to model here.
any()
}
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { n instanceof OperandNode and not n instanceof ArgumentNode }
predicate nodeIsHidden(Node n) {
n instanceof OperandNode and not n instanceof ArgumentNode
or
StoreNodeFlow::flowThrough(n, _) and
not StoreNodeFlow::flowOutOf(n, _) and
not StoreNodeFlow::flowInto(_, n)
or
ReadNodeFlow::flowThrough(n, _) and
not ReadNodeFlow::flowOutOf(n, _) and
not ReadNodeFlow::flowInto(_, n)
}
class LambdaCallKind = Unit;
@@ -320,3 +325,11 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
override predicate argHasPostUpdateExclude(ArgumentNode n) {
// The rules for whether an IR argument gets a post-update node are too
// complex to model here.
any()
}
}

View File

@@ -452,7 +452,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
/** Holds if this phi node has input from the `rnk`'th write operation in block `block`. */
final predicate hasInputAtRankInBlock(IRBlock block, int rnk) {
hasInputAtRankInBlock(block, rnk, _)
this.hasInputAtRankInBlock(block, rnk, _)
}
/**
@@ -806,7 +806,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand())
or
// Flow into, through, and out of store nodes
StoreNodeFlow::flowInto(nodeFrom, nodeTo)
StoreNodeFlow::flowInto(nodeFrom.asInstruction(), nodeTo)
or
StoreNodeFlow::flowThrough(nodeFrom, nodeTo)
or
@@ -831,23 +831,19 @@ private predicate adjacentDefUseFlow(Node nodeFrom, Node nodeTo) {
//Def-use flow
Ssa::ssaFlow(nodeFrom, nodeTo)
or
exists(Instruction loadAddress | loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) |
// Use-use flow through reads
exists(Node address |
Ssa::addressFlowTC(address.asInstruction(), loadAddress) and
Ssa::ssaFlow(address, nodeTo)
)
or
// Use-use flow through stores.
exists(Node store |
Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and
Ssa::ssaFlow(store, nodeTo)
)
// Use-use flow through stores.
exists(Instruction loadAddress, Node store |
loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) and
Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and
Ssa::ssaFlow(store, nodeTo)
)
)
}
private module ReadNodeFlow {
/**
* INTERNAL: Do not use.
*/
module ReadNodeFlow {
/** Holds if the read node `nodeTo` should receive flow from `nodeFrom`. */
predicate flowInto(Node nodeFrom, ReadNode nodeTo) {
nodeTo.isInitial() and
@@ -867,7 +863,12 @@ private module ReadNodeFlow {
)
}
/** Holds if the read node `nodeTo` should receive flow from the read node `nodeFrom`. */
/**
* Holds if the read node `nodeTo` should receive flow from the read node `nodeFrom`.
*
* This happens when `readFrom` is _not_ the source of a `readStep`, and `nodeTo` is
* the `ReadNode` that represents an address that directly depends on `nodeFrom`.
*/
predicate flowThrough(ReadNode nodeFrom, ReadNode nodeTo) {
not readStep(nodeFrom, _, _) and
nodeFrom.getOuter() = nodeTo
@@ -906,17 +907,25 @@ private module ReadNodeFlow {
}
}
private module StoreNodeFlow {
/**
* INTERNAL: Do not use.
*/
module StoreNodeFlow {
/** Holds if the store node `nodeTo` should receive flow from `nodeFrom`. */
predicate flowInto(Node nodeFrom, StoreNode nodeTo) {
nodeTo.flowInto(Ssa::getDestinationAddress(nodeFrom.asInstruction()))
predicate flowInto(Instruction instrFrom, StoreNode nodeTo) {
nodeTo.flowInto(Ssa::getDestinationAddress(instrFrom))
}
/** Holds if the store node `nodeTo` should receive flow from `nodeFom`. */
predicate flowThrough(StoreNode nFrom, StoreNode nodeTo) {
/**
* Holds if the store node `nodeTo` should receive flow from `nodeFom`.
*
* This happens when `nodeFrom` is _not_ the source of a `storeStep`, and `nodeFrom` is
* the `Storenode` that represents an address that directly depends on `nodeTo`.
*/
predicate flowThrough(StoreNode nodeFrom, StoreNode nodeTo) {
// Flow through a post update node that doesn't need a store step.
not storeStep(nFrom, _, _) and
nodeTo.getOuter() = nFrom
not storeStep(nodeFrom, _, _) and
nodeTo.getOuter() = nodeFrom
}
/**

View File

@@ -634,3 +634,29 @@ class UncertainWriteDefinition extends WriteDefinition {
)
}
}
/** Provides a set of consistency queries. */
module Consistency {
abstract class RelevantDefinition extends Definition {
abstract predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
);
}
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefReachesRead(v, def, bb, i) and
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
}
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
variableRead(bb, i, v, _) and
not ssaDefReachesRead(v, _, bb, i)
}
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
v = def.getSourceVariable() and
not ssaDefReachesRead(_, def, _, _) and
not phiHasInputFromBlock(_, def, _) and
not uncertainWriteDefinitionInput(_, def)
}
}

View File

@@ -244,17 +244,6 @@ Instruction getDestinationAddress(Instruction instr) {
]
}
class ReferenceToInstruction extends CopyValueInstruction {
ReferenceToInstruction() {
this.getResultType() instanceof Cpp::ReferenceType and
not this.getUnary().getResultType() instanceof Cpp::ReferenceType
}
Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() }
Operand getSourceAddressOperand() { result = this.getUnaryOperand() }
}
/** Gets the source address of `instr` if it is an instruction that behaves like a `LoadInstruction`. */
Instruction getSourceAddress(Instruction instr) { result = getSourceAddressOperand(instr).getDef() }
@@ -266,11 +255,7 @@ Operand getSourceAddressOperand(Instruction instr) {
result =
[
instr.(LoadInstruction).getSourceAddressOperand(),
instr.(ReadSideEffectInstruction).getArgumentOperand(),
// `ReferenceToInstruction` is really more of an address-of operation,
// but by including it in this list we break out of `flowOutOfAddressStep` at an
// instruction that, at the source level, looks like a use of a variable.
instr.(ReferenceToInstruction).getSourceAddressOperand()
instr.(ReadSideEffectInstruction).getArgumentOperand()
]
}
@@ -295,10 +280,6 @@ Operand getSourceValueOperand(Instruction instr) {
result = instr.(LoadInstruction).getSourceValueOperand()
or
result = instr.(ReadSideEffectInstruction).getSideEffectOperand()
or
// See the comment on the `ReferenceToInstruction` disjunct in `getSourceAddressOperand` for why
// this case is included.
result = instr.(ReferenceToInstruction).getSourceValueOperand()
}
/**
@@ -513,6 +494,64 @@ private module Cached {
explicitWrite(false, storeNode.getStoreInstruction(), def)
)
or
// The destination of a store operation has undergone lvalue-to-rvalue conversion and is now a
// right-hand-side of a store operation.
// Find the next use of the variable in that store operation, and recursively find the load of that
// pointer. For example, consider this case:
//
// ```cpp
// int x = source();
// int* p = &x;
// sink(*p);
// ```
//
// if we want to find the load of the address of `x`, we see that the pointer is stored into `p`,
// and we then need to recursively look for the load of `p`.
exists(
Def def, StoreInstruction store, IRBlock block1, int rnk1, Use use, IRBlock block2, int rnk2
|
store = def.getInstruction() and
store.getSourceValueOperand() = operand and
def.hasRankInBlock(block1, rnk1) and
use.hasRankInBlock(block2, rnk2) and
adjacentDefRead(_, block1, rnk1, block2, rnk2)
|
// The shared SSA library has determined that `use` is the next use of the operand
// so we find the next load of that use (but only if there is no `PostUpdateNode`) we
// need to flow into first.
not StoreNodeFlow::flowInto(store, _) and
flowOutOfAddressStep(use.getOperand(), nodeTo)
or
// It may also be the case that `store` gives rise to another store step. So let's make sure that
// we also take those into account.
StoreNodeFlow::flowInto(store, nodeTo)
)
or
// As we find the next load of an address, we might come across another use of the same variable.
// In that case, we recursively find the next use of _that_ operand, and continue searching for
// the next load of that operand. For example, consider this case:
//
// ```cpp
// int x = source();
// use(&x);
// int* p = &x;
// sink(*p);
// ```
//
// The next use of `x` after its definition is `use(&x)`, but there is a later load of the address
// of `x` that we want to flow to. So we use the shared SSA library to find the next load.
not operand = getSourceAddressOperand(_) and
exists(Use use1, Use use2, IRBlock block1, int rnk1, IRBlock block2, int rnk2 |
use1.getOperand() = operand and
use1.hasRankInBlock(block1, rnk1) and
// Don't flow to the next use if this use is part of a store operation that totally
// overrides a variable.
not explicitWrite(true, _, use1.getOperand().getDef()) and
adjacentDefRead(_, block1, rnk1, block2, rnk2) and
use2.hasRankInBlock(block2, rnk2) and
flowOutOfAddressStep(use2.getOperand(), nodeTo)
)
or
operand = getSourceAddressOperand(nodeTo.asInstruction())
or
exists(ReturnIndirectionInstruction ret |

View File

@@ -20,6 +20,14 @@ private import internal.OperandInternal
private class TStageOperand =
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
/**
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
* opposed to testing `not loc isntanceof UnknownLocation`
*/
private class KnownLocation extends Language::Location {
KnownLocation() { not this instanceof Language::UnknownLocation }
}
/**
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
* (the defining instruction) in another instruction (the use instruction)
@@ -45,8 +53,10 @@ class Operand extends TStageOperand {
/**
* Gets the location of the source code for this operand.
* By default this is where the operand is used, but some subclasses may override this
* using `getAnyDef()` if it makes more sense.
*/
final Language::Location getLocation() { result = this.getUse().getLocation() }
Language::Location getLocation() { result = this.getUse().getLocation() }
/**
* Gets the function that contains this operand.
@@ -269,6 +279,10 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
final override string toString() { result = tag.toString() }
// most `RegisterOperands` have a more meaningful location at the definition
// the only exception are specific cases of `ThisArgumentOperand`
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
final override Instruction getAnyDef() { result = defInstr }
final override Overlap getDefinitionOverlap() {
@@ -293,7 +307,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
final override string toString() { result = tag.toString() }
final override Instruction getAnyDef() {
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
}
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
@@ -401,11 +415,19 @@ class ArgumentOperand extends RegisterOperand {
}
/**
* An operand representing the implicit 'this' argument to a member function
* An operand representing the implicit `this` argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
override ThisArgumentOperandTag tag;
// in most cases the def location makes more sense, but in some corner cases it
// has an unknown location: in those cases we fall back to the use location
override Language::Location getLocation() {
if this.getAnyDef().getLocation() instanceof KnownLocation
then result = this.getAnyDef().getLocation()
else result = this.getUse().getLocation()
}
}
/**

View File

@@ -20,6 +20,14 @@ private import internal.OperandInternal
private class TStageOperand =
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
/**
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
* opposed to testing `not loc isntanceof UnknownLocation`
*/
private class KnownLocation extends Language::Location {
KnownLocation() { not this instanceof Language::UnknownLocation }
}
/**
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
* (the defining instruction) in another instruction (the use instruction)
@@ -45,8 +53,10 @@ class Operand extends TStageOperand {
/**
* Gets the location of the source code for this operand.
* By default this is where the operand is used, but some subclasses may override this
* using `getAnyDef()` if it makes more sense.
*/
final Language::Location getLocation() { result = this.getUse().getLocation() }
Language::Location getLocation() { result = this.getUse().getLocation() }
/**
* Gets the function that contains this operand.
@@ -269,6 +279,10 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
final override string toString() { result = tag.toString() }
// most `RegisterOperands` have a more meaningful location at the definition
// the only exception are specific cases of `ThisArgumentOperand`
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
final override Instruction getAnyDef() { result = defInstr }
final override Overlap getDefinitionOverlap() {
@@ -293,7 +307,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
final override string toString() { result = tag.toString() }
final override Instruction getAnyDef() {
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
}
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
@@ -401,11 +415,19 @@ class ArgumentOperand extends RegisterOperand {
}
/**
* An operand representing the implicit 'this' argument to a member function
* An operand representing the implicit `this` argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
override ThisArgumentOperandTag tag;
// in most cases the def location makes more sense, but in some corner cases it
// has an unknown location: in those cases we fall back to the use location
override Language::Location getLocation() {
if this.getAnyDef().getLocation() instanceof KnownLocation
then result = this.getAnyDef().getLocation()
else result = this.getUse().getLocation()
}
}
/**

View File

@@ -20,6 +20,14 @@ private import internal.OperandInternal
private class TStageOperand =
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
/**
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
* opposed to testing `not loc isntanceof UnknownLocation`
*/
private class KnownLocation extends Language::Location {
KnownLocation() { not this instanceof Language::UnknownLocation }
}
/**
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
* (the defining instruction) in another instruction (the use instruction)
@@ -45,8 +53,10 @@ class Operand extends TStageOperand {
/**
* Gets the location of the source code for this operand.
* By default this is where the operand is used, but some subclasses may override this
* using `getAnyDef()` if it makes more sense.
*/
final Language::Location getLocation() { result = this.getUse().getLocation() }
Language::Location getLocation() { result = this.getUse().getLocation() }
/**
* Gets the function that contains this operand.
@@ -269,6 +279,10 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
final override string toString() { result = tag.toString() }
// most `RegisterOperands` have a more meaningful location at the definition
// the only exception are specific cases of `ThisArgumentOperand`
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
final override Instruction getAnyDef() { result = defInstr }
final override Overlap getDefinitionOverlap() {
@@ -293,7 +307,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
final override string toString() { result = tag.toString() }
final override Instruction getAnyDef() {
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
}
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
@@ -401,11 +415,19 @@ class ArgumentOperand extends RegisterOperand {
}
/**
* An operand representing the implicit 'this' argument to a member function
* An operand representing the implicit `this` argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
override ThisArgumentOperandTag tag;
// in most cases the def location makes more sense, but in some corner cases it
// has an unknown location: in those cases we fall back to the use location
override Language::Location getLocation() {
if this.getAnyDef().getLocation() instanceof KnownLocation
then result = this.getAnyDef().getLocation()
else result = this.getUse().getLocation()
}
}
/**

View File

@@ -18,12 +18,12 @@ class SuppressionComment extends Comment {
(
this instanceof CppStyleComment and
// strip the beginning slashes
text = getContents().suffix(2)
text = this.getContents().suffix(2)
or
this instanceof CStyleComment and
// strip both the beginning /* and the end */ the comment
exists(string text0 |
text0 = getContents().suffix(2) and
text0 = this.getContents().suffix(2) and
text = text0.prefix(text0.length() - 2)
) and
// The /* */ comment must be a single-line comment

View File

@@ -153,12 +153,12 @@ class ExtClass extends Class {
}
predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) {
if hasOneVariableGroup()
if this.hasOneVariableGroup()
then
exists(VariableDeclarationGroup vdg | vdg.getClass() = this |
vdg.hasLocationInfo(path, startline, startcol, endline, endcol)
)
else getLocation().hasLocationInfo(path, startline, startcol, endline, endcol)
else this.getLocation().hasLocationInfo(path, startline, startcol, endline, endcol)
}
}

View File

@@ -50,6 +50,16 @@ predicate reachableThing(Thing t) {
exists(Thing mid | reachableThing(mid) and mid.callsOrAccesses() = t)
}
pragma[nomagic]
predicate callsOrAccessesPlus(Thing thing1, FunctionToRemove thing2) {
thing1.callsOrAccesses() = thing2
or
exists(Thing mid |
thing1.callsOrAccesses() = mid and
callsOrAccessesPlus(mid, thing2)
)
}
class Thing extends Locatable {
Thing() {
this instanceof Function or
@@ -81,7 +91,7 @@ class FunctionToRemove extends Function {
}
Thing getOther() {
result.callsOrAccesses+() = this and
callsOrAccessesPlus(result, this) and
this != result and
// We will already be reporting the enclosing function of a
// local variable, so don't also report the variable

7
cpp/ql/src/CHANGELOG.md Normal file
View File

@@ -0,0 +1,7 @@
## 0.0.5
## 0.0.4
### New Queries
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.

View File

@@ -103,9 +103,9 @@ class CallWithBufferSize extends FunctionCall {
// `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
// result in this case we pick the minimum value obtainable from dataflow and range analysis.
result =
upperBound(statedSizeExpr())
upperBound(this.statedSizeExpr())
.minimum(min(Expr statedSizeSrc |
DataFlow::localExprFlow(statedSizeSrc, statedSizeExpr())
DataFlow::localExprFlow(statedSizeSrc, this.statedSizeExpr())
|
statedSizeSrc.getValue().toInt()
))

View File

@@ -22,7 +22,7 @@ abstract class LockOperation extends FunctionCall {
ControlFlowNode getAReachedNode() {
result = this
or
exists(ControlFlowNode mid | mid = getAReachedNode() |
exists(ControlFlowNode mid | mid = this.getAReachedNode() |
not mid != this.getMatchingUnlock() and
result = mid.getASuccessor()
)

View File

@@ -156,8 +156,8 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
//
// https://aa.usno.navy.mil/faq/docs/calendars.php
this.isUsedInMod4Operation() and
additionalModulusCheckForLeapYear(400) and
additionalModulusCheckForLeapYear(100)
this.additionalModulusCheckForLeapYear(400) and
this.additionalModulusCheckForLeapYear(100)
}
}
@@ -176,17 +176,17 @@ class StructTmLeapYearFieldAccess extends LeapYearFieldAccess {
override predicate isUsedInCorrectLeapYearCheck() {
this.isUsedInMod4Operation() and
additionalModulusCheckForLeapYear(400) and
additionalModulusCheckForLeapYear(100) and
this.additionalModulusCheckForLeapYear(400) and
this.additionalModulusCheckForLeapYear(100) and
// tm_year represents years since 1900
(
additionalAdditionOrSubstractionCheckForLeapYear(1900)
this.additionalAdditionOrSubstractionCheckForLeapYear(1900)
or
// some systems may use 2000 for 2-digit year conversions
additionalAdditionOrSubstractionCheckForLeapYear(2000)
this.additionalAdditionOrSubstractionCheckForLeapYear(2000)
or
// converting from/to Unix epoch
additionalAdditionOrSubstractionCheckForLeapYear(1970)
this.additionalAdditionOrSubstractionCheckForLeapYear(1970)
)
}
}

View File

@@ -57,7 +57,7 @@ class LoopWithAlloca extends Stmt {
or
// `e == 0`
exists(EQExpr eq |
conditionRequires(eq, truth.booleanNot()) and
this.conditionRequires(eq, truth.booleanNot()) and
eq.getAnOperand().getValue().toInt() = 0 and
e = eq.getAnOperand() and
not exists(e.getValue())
@@ -65,7 +65,7 @@ class LoopWithAlloca extends Stmt {
or
// `e != 0`
exists(NEExpr eq |
conditionRequires(eq, truth) and
this.conditionRequires(eq, truth) and
eq.getAnOperand().getValue().toInt() = 0 and
e = eq.getAnOperand() and
not exists(e.getValue())
@@ -73,7 +73,7 @@ class LoopWithAlloca extends Stmt {
or
// `(bool)e == true`
exists(EQExpr eq |
conditionRequires(eq, truth) and
this.conditionRequires(eq, truth) and
eq.getAnOperand().getValue().toInt() = 1 and
e = eq.getAnOperand() and
e.getUnspecifiedType() instanceof BoolType and
@@ -82,7 +82,7 @@ class LoopWithAlloca extends Stmt {
or
// `(bool)e != true`
exists(NEExpr eq |
conditionRequires(eq, truth.booleanNot()) and
this.conditionRequires(eq, truth.booleanNot()) and
eq.getAnOperand().getValue().toInt() = 1 and
e = eq.getAnOperand() and
e.getUnspecifiedType() instanceof BoolType and
@@ -90,7 +90,7 @@ class LoopWithAlloca extends Stmt {
)
or
exists(NotExpr notExpr |
conditionRequires(notExpr, truth.booleanNot()) and
this.conditionRequires(notExpr, truth.booleanNot()) and
e = notExpr.getOperand()
)
or
@@ -98,7 +98,7 @@ class LoopWithAlloca extends Stmt {
// requires both of its operand to be true as well.
exists(LogicalAndExpr andExpr |
truth = true and
conditionRequires(andExpr, truth) and
this.conditionRequires(andExpr, truth) and
e = andExpr.getAnOperand()
)
or
@@ -106,7 +106,7 @@ class LoopWithAlloca extends Stmt {
// it requires both of its operand to be false as well.
exists(LogicalOrExpr orExpr |
truth = false and
conditionRequires(orExpr, truth) and
this.conditionRequires(orExpr, truth) and
e = orExpr.getAnOperand()
)
}
@@ -141,9 +141,9 @@ class LoopWithAlloca extends Stmt {
* `conditionRequiresInequality`.
*/
private Variable getAControllingVariable() {
conditionRequires(result.getAnAccess(), _)
this.conditionRequires(result.getAnAccess(), _)
or
conditionRequiresInequality(result.getAnAccess(), _, _)
this.conditionRequiresInequality(result.getAnAccess(), _, _)
}
/**

View File

@@ -61,72 +61,72 @@ class PointerArithmeticAccess extends BufferAccess, Expr {
* A pair of buffer accesses through a call to memcpy.
*/
class MemCpy extends BufferAccess, FunctionCall {
MemCpy() { getTarget().hasName("memcpy") }
MemCpy() { this.getTarget().hasName("memcpy") }
override Expr getPointer() {
result = getArgument(0) or
result = getArgument(1)
result = this.getArgument(0) or
result = this.getArgument(1)
}
override Expr getAccessedLength() { result = getArgument(2) }
override Expr getAccessedLength() { result = this.getArgument(2) }
}
class StrncpySizeExpr extends BufferAccess, FunctionCall {
StrncpySizeExpr() { getTarget().hasName("strncpy") }
StrncpySizeExpr() { this.getTarget().hasName("strncpy") }
override Expr getPointer() {
result = getArgument(0) or
result = getArgument(1)
result = this.getArgument(0) or
result = this.getArgument(1)
}
override Expr getAccessedLength() { result = getArgument(2) }
override Expr getAccessedLength() { result = this.getArgument(2) }
}
class RecvSizeExpr extends BufferAccess, FunctionCall {
RecvSizeExpr() { getTarget().hasName("recv") }
RecvSizeExpr() { this.getTarget().hasName("recv") }
override Expr getPointer() { result = getArgument(1) }
override Expr getPointer() { result = this.getArgument(1) }
override Expr getAccessedLength() { result = getArgument(2) }
override Expr getAccessedLength() { result = this.getArgument(2) }
}
class SendSizeExpr extends BufferAccess, FunctionCall {
SendSizeExpr() { getTarget().hasName("send") }
SendSizeExpr() { this.getTarget().hasName("send") }
override Expr getPointer() { result = getArgument(1) }
override Expr getPointer() { result = this.getArgument(1) }
override Expr getAccessedLength() { result = getArgument(2) }
override Expr getAccessedLength() { result = this.getArgument(2) }
}
class SnprintfSizeExpr extends BufferAccess, FunctionCall {
SnprintfSizeExpr() { getTarget().hasName("snprintf") }
SnprintfSizeExpr() { this.getTarget().hasName("snprintf") }
override Expr getPointer() { result = getArgument(0) }
override Expr getPointer() { result = this.getArgument(0) }
override Expr getAccessedLength() { result = getArgument(1) }
override Expr getAccessedLength() { result = this.getArgument(1) }
}
class MemcmpSizeExpr extends BufferAccess, FunctionCall {
MemcmpSizeExpr() { getTarget().hasName("Memcmp") }
MemcmpSizeExpr() { this.getTarget().hasName("Memcmp") }
override Expr getPointer() {
result = getArgument(0) or
result = getArgument(1)
result = this.getArgument(0) or
result = this.getArgument(1)
}
override Expr getAccessedLength() { result = getArgument(2) }
override Expr getAccessedLength() { result = this.getArgument(2) }
}
class MallocSizeExpr extends BufferAccess, FunctionCall {
MallocSizeExpr() { getTarget().hasName("malloc") }
MallocSizeExpr() { this.getTarget().hasName("malloc") }
override Expr getPointer() { none() }
override Expr getAccessedLength() { result = getArgument(0) }
override Expr getAccessedLength() { result = this.getArgument(0) }
}
class NetworkFunctionCall extends FunctionCall {
NetworkFunctionCall() { getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
NetworkFunctionCall() { this.getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
}
class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {

View File

@@ -3,8 +3,10 @@
* @description Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols, or disabling minimum-recommended protocols.
* @kind problem
* @problem.severity error
* @security-severity 7.5
* @id cpp/boost/tls-settings-misconfiguration
* @tags security
* external/cwe/cwe-326
*/
import cpp

View File

@@ -3,8 +3,10 @@
* @description Using a deprecated hard-coded protocol using the boost::asio library.
* @kind problem
* @problem.severity error
* @security-severity 7.5
* @id cpp/boost/use-of-deprecated-hardcoded-security-protocol
* @tags security
* external/cwe/cwe-327
*/
import cpp

View File

@@ -13,7 +13,7 @@ import cpp
class MacroFunctionCall extends MacroInvocation {
MacroFunctionCall() {
not exists(getParentInvocation()) and
not exists(this.getParentInvocation()) and
this.getMacro().getHead().matches("%(%")
}

View File

@@ -13,7 +13,7 @@ import semmle.code.cpp.commons.Assertions
class MacroFunctionCall extends MacroInvocation {
MacroFunctionCall() {
not exists(getParentInvocation()) and
not exists(this.getParentInvocation()) and
this.getMacro().getHead().matches("%(%")
}

View File

@@ -38,7 +38,7 @@ class ExternalAPIDataNode extends DataFlow::Node {
int getIndex() { result = i }
/** Gets the description of the function being called. */
string getFunctionDescription() { result = getExternalFunction().toString() }
string getFunctionDescription() { result = this.getExternalFunction().toString() }
}
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */

View File

@@ -38,7 +38,7 @@ class ExternalAPIDataNode extends DataFlow::Node {
int getIndex() { result = i }
/** Gets the description of the function being called. */
string getFunctionDescription() { result = getExternalFunction().toString() }
string getFunctionDescription() { result = this.getExternalFunction().toString() }
}
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */

View File

@@ -42,7 +42,7 @@ class VarargsFunction extends Function {
}
private int trailingArgValueCount(string value) {
result = strictcount(FunctionCall fc | trailingArgValue(fc) = value)
result = strictcount(FunctionCall fc | this.trailingArgValue(fc) = value)
}
string nonTrailingVarArgValue(FunctionCall fc, int index) {
@@ -58,11 +58,11 @@ class VarargsFunction extends Function {
string normalTerminator(int cnt) {
result = ["0", "-1"] and
cnt = trailingArgValueCount(result) and
2 * cnt > totalCount() and
cnt = this.trailingArgValueCount(result) and
2 * cnt > this.totalCount() and
not exists(FunctionCall fc, int index |
// terminator value is used in a non-terminating position
nonTrailingVarArgValue(fc, index) = result
this.nonTrailingVarArgValue(fc, index) = result
)
}

View File

@@ -42,7 +42,7 @@ class TaintSource extends VariableAccess {
definitionUsePair(_, this, va)
or
exists(VariableAccess mid, Expr def |
sourceReaches(mid) and
this.sourceReaches(mid) and
exprDefinition(_, def, mid) and
definitionUsePair(_, def, va)
)
@@ -53,11 +53,11 @@ class TaintSource extends VariableAccess {
* from `va`, possibly using intermediate reassignments.
*/
private predicate reachesSink(VariableAccess va, VariableAccess sink) {
isSink(sink) and
this.isSink(sink) and
va = sink
or
exists(VariableAccess mid, Expr def |
reachesSink(mid, sink) and
this.reachesSink(mid, sink) and
exprDefinition(_, def, va) and
definitionUsePair(_, def, mid)
)
@@ -71,15 +71,15 @@ class TaintSource extends VariableAccess {
* this source to `sink` found via `tainted(source, sink)`.)
*/
predicate reaches(VariableAccess sink) {
isSink(sink) and
this.isSink(sink) and
not exists(VariableAccess va |
va != this and
va != sink and
mayAddNullTerminator(_, va)
|
sourceReaches(va)
this.sourceReaches(va)
or
reachesSink(va, sink)
this.reachesSink(va, sink)
)
}
}

View File

@@ -0,0 +1,28 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>When checking the result of SSL certificate verification, accepting any error code may allow an attacker to impersonate someone who is trusted.</p>
</overview>
<recommendation>
<p>When checking an SSL certificate with <code>SSL_get_verify_result</code>, only <code>X509_V_OK</code> is a success code. If there is any other result the certificate should not be accepted.</p>
</recommendation>
<example>
<p>In this example the error code <code>X509_V_ERR_CERT_HAS_EXPIRED</code> is treated the same as an OK result. An expired certificate should not be accepted as it is more likely to be compromised than a valid certificate.</p>
<sample src="SSLResultConflationBad.cpp" />
<p>In the corrected example, only a result of <code>X509_V_OK</code> is accepted.</p>
<sample src="SSLResultConflationGood.cpp" />
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,50 @@
/**
* @name Certificate result conflation
* @description Only accept SSL certificates that pass certificate verification.
* @kind problem
* @problem.severity error
* @security-severity 7.5
* @precision medium
* @id cpp/certificate-result-conflation
* @tags security
* external/cwe/cwe-295
*/
import cpp
import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.dataflow.DataFlow
/**
* A call to `SSL_get_verify_result`.
*/
class SSLGetVerifyResultCall extends FunctionCall {
SSLGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
}
/**
* Data flow from a call to `SSL_get_verify_result` to a guard condition
* that references the result.
*/
class VerifyResultConfig extends DataFlow::Configuration {
VerifyResultConfig() { this = "VerifyResultConfig" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof SSLGetVerifyResultCall
}
override predicate isSink(DataFlow::Node sink) {
exists(GuardCondition guard | guard.getAChild*() = sink.asExpr())
}
}
from
VerifyResultConfig config, DataFlow::Node source, DataFlow::Node sink1, DataFlow::Node sink2,
GuardCondition guard, Expr c1, Expr c2, boolean testIsTrue
where
config.hasFlow(source, sink1) and
config.hasFlow(source, sink2) and
guard.comparesEq(sink1.asExpr(), c1, 0, false, testIsTrue) and // (value != c1) => testIsTrue
guard.comparesEq(sink2.asExpr(), c2, 0, false, testIsTrue) and // (value != c2) => testIsTrue
c1.getValue().toInt() = 0 and
c2.getValue().toInt() != 0
select guard, "This expression conflates OK and non-OK results from $@.", source, source.toString()

View File

@@ -0,0 +1,13 @@
// ...
if (cert = SSL_get_peer_certificate(ssl))
{
result = SSL_get_verify_result(ssl);
if ((result == X509_V_OK) || (result == X509_V_ERR_CERT_HAS_EXPIRED)) // BAD (conflates OK and a non-OK codes)
{
do_ok();
} else {
do_error();
}
}

View File

@@ -0,0 +1,13 @@
// ...
if (cert = SSL_get_peer_certificate(ssl))
{
result = SSL_get_verify_result(ssl);
if (result == X509_V_OK) // GOOD
{
do_ok();
} else {
do_error();
}
}

View File

@@ -0,0 +1,28 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>After fetching an SSL certificate, always check the result of certificate verification.</p>
</overview>
<recommendation>
<p>Always check the result of SSL certificate verification. A certificate that has been revoked may indicate that data is coming from an attacker, whereas a certificate that has expired or was self-signed may indicate an increased likelihood that the data is malicious.</p>
</recommendation>
<example>
<p>In this example, the <code>SSL_get_peer_certificate</code> function is used to get the certificate of a peer. However it is unsafe to use that information without checking if the certificate is valid.</p>
<sample src="SSLResultNotCheckedBad.cpp" />
<p>In the corrected example, we use <code>SSL_get_verify_result</code> to check that certificate verification was successful.</p>
<sample src="SSLResultNotCheckedGood.cpp" />
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,120 @@
/**
* @name Certificate not checked
* @description Always check the result of certificate verification after fetching an SSL certificate.
* @kind problem
* @problem.severity error
* @security-severity 7.5
* @precision medium
* @id cpp/certificate-not-checked
* @tags security
* external/cwe/cwe-295
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.controlflow.IRGuards
/**
* A call to `SSL_get_peer_certificate`.
*/
class SSLGetPeerCertificateCall extends FunctionCall {
SSLGetPeerCertificateCall() {
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl)
}
Expr getSSLArgument() { result = getArgument(0) }
}
/**
* A call to `SSL_get_verify_result`.
*/
class SSLGetVerifyResultCall extends FunctionCall {
SSLGetVerifyResultCall() {
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl)
}
Expr getSSLArgument() { result = getArgument(0) }
}
/**
* Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
* `SSL_get_verify_result` entering `node`.
*/
predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
exists(Expr ssl, SSLGetVerifyResultCall check |
ssl = globalValueNumber(getCertCall.getSSLArgument()).getAnExpr() and
ssl = check.getSSLArgument() and
node = check
)
}
/**
* Holds if the certificate returned by `SSL_get_peer_certificate` is found to be
* `0` on the edge `node1` to `node2`.
*/
predicate certIsZero(
SSLGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
) {
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
exists(GuardCondition guard, Expr zero |
zero.getValue().toInt() = 0 and
node1 = guard and
(
// if (cert == zero) {
guard.comparesEq(cert, zero, 0, true, true) and
node2 = guard.getATrueSuccessor()
or
// if (cert != zero) { }
guard.comparesEq(cert, zero, 0, false, true) and
node2 = guard.getAFalseSuccessor()
)
)
or
(
// if (cert) { }
node1 = cert
or
// if (!cert) {
node1.(NotExpr).getAChild() = cert
) and
node2 = node1.getASuccessor() and
not cert.(GuardCondition).controls(node2, true) // cert may be false
)
}
/**
* Holds if the SSL object passed into `SSL_get_peer_certificate` has not been checked with
* `SSL_get_verify_result` at `node`. Note that this is only computed at the call to
* `SSL_get_peer_certificate` and at the start and end of `BasicBlock`s.
*/
predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
// cert is not checked at the call to `SSL_get_peer_certificate`
node = getCertCall
or
exists(BasicBlock bb, int pos |
// flow to end of a `BasicBlock`
certNotChecked(getCertCall, bb.getNode(pos)) and
node = bb.getEnd() and
// check for barrier node
not exists(int pos2 |
pos2 > pos and
resultIsChecked(getCertCall, bb.getNode(pos2))
)
)
or
exists(BasicBlock pred, BasicBlock bb |
// flow from the end of one `BasicBlock` to the beginning of a successor
certNotChecked(getCertCall, pred.getEnd()) and
bb = pred.getASuccessor() and
node = bb.getStart() and
// check for barrier bb
not certIsZero(getCertCall, pred.getEnd(), bb.getStart())
)
}
from SSLGetPeerCertificateCall getCertCall, ControlFlowNode node
where
certNotChecked(getCertCall, node) and
node instanceof Function // (function exit)
select getCertCall,
"This " + getCertCall.toString() + " is not followed by a call to SSL_get_verify_result."

View File

@@ -0,0 +1,5 @@
// ...
X509 *cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is never called)
// ...

View File

@@ -0,0 +1,9 @@
// ...
X509 *cert = SSL_get_peer_certificate(ssl); // GOOD
if (cert)
{
result = SSL_get_verify_result(ssl);
if (result == X509_V_OK)
{
// ...

View File

@@ -8,6 +8,7 @@
* @precision high
* @id cpp/cleartext-storage-file
* @tags security
* external/cwe/cwe-260
* external/cwe/cwe-313
*/

View File

@@ -29,7 +29,7 @@ class SqliteFunctionCall extends FunctionCall {
}
predicate sqlite_encryption_used() {
any(StringLiteral l).getValue().toLowerCase().regexpMatch("pragma key.*") or
any(StringLiteral l).getValue().toLowerCase().matches("pragma key%") or
any(StringLiteral l).getValue().toLowerCase().matches("%attach%database%key%") or
any(FunctionCall fc).getTarget().getName().matches("sqlite%\\_key\\_%")
}

View File

@@ -84,8 +84,8 @@ class ParameterNullCheck extends ParameterCheck {
p.getFunction() instanceof InitializationFunction and
p.getType().getUnspecifiedType() instanceof PointerType and
exists(VariableAccess va | va = p.getAnAccess() |
nullSuccessor = getATrueSuccessor() and
notNullSuccessor = getAFalseSuccessor() and
nullSuccessor = this.getATrueSuccessor() and
notNullSuccessor = this.getAFalseSuccessor() and
(
va = this.(NotExpr).getOperand() or
va = any(EQExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
@@ -95,8 +95,8 @@ class ParameterNullCheck extends ParameterCheck {
.getAnOperand()
)
or
nullSuccessor = getAFalseSuccessor() and
notNullSuccessor = getATrueSuccessor() and
nullSuccessor = this.getAFalseSuccessor() and
notNullSuccessor = this.getATrueSuccessor() and
(
va = this or
va = any(NEExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
@@ -132,7 +132,7 @@ class ValidatedExternalCondInitFunction extends ExternalData {
ValidatedExternalCondInitFunction() { this.getDataPath().matches("%cond-init%.csv") }
predicate isExternallyVerified(Function f, int param) {
functionSignature(f, getField(1), getField(2)) and param = getFieldAsInt(3)
functionSignature(f, this.getField(1), this.getField(2)) and param = this.getFieldAsInt(3)
}
}
@@ -193,7 +193,7 @@ class InitializationFunction extends Function {
.getAnOverridingFunction+()
.(InitializationFunction)
.initializedParameter() or
getParameter(i) = any(InitializationFunctionCall c).getAnInitParameter()
this.getParameter(i) = any(InitializationFunctionCall c).getAnInitParameter()
)
or
// If we have no definition, we look at SAL annotations
@@ -227,7 +227,7 @@ class InitializationFunction extends Function {
result = getAnInitializedArgument(any(Call c))
or
exists(IfStmt check | result = check.getCondition().getAChild*() |
paramReassignmentCondition(check)
this.paramReassignmentCondition(check)
)
)
or
@@ -249,15 +249,15 @@ class InitializationFunction extends Function {
/** Holds if `n` can be reached without the parameter at `index` being reassigned. */
predicate paramNotReassignedAt(ControlFlowNode n, int index, Context c) {
c = getAContext(index) and
c = this.getAContext(index) and
(
not exists(this.getEntryPoint()) and index = i and n = this
or
n = this.getEntryPoint() and index = i
or
exists(ControlFlowNode mid | paramNotReassignedAt(mid, index, c) |
exists(ControlFlowNode mid | this.paramNotReassignedAt(mid, index, c) |
n = mid.getASuccessor() and
not n = paramReassignment(index) and
not n = this.paramReassignment(index) and
/*
* Ignore successor edges where the parameter is null, because it is then confirmed to be
* initialized.
@@ -265,7 +265,7 @@ class InitializationFunction extends Function {
not exists(ParameterNullCheck nullCheck |
nullCheck = mid and
nullCheck = getANullCheck(index) and
nullCheck = this.getANullCheck(index) and
n = nullCheck.getNullSuccessor()
) and
/*
@@ -281,13 +281,13 @@ class InitializationFunction extends Function {
/** Gets a null-check on the parameter at `index`. */
private ParameterNullCheck getANullCheck(int index) {
getParameter(index) = result.getParameter()
this.getParameter(index) = result.getParameter()
}
/** Gets a parameter which is not at the given index. */
private Parameter getOtherParameter(int index) {
index = i and
result = getAParameter() and
result = this.getAParameter() and
not result.getIndex() = index
}
@@ -306,10 +306,10 @@ class InitializationFunction extends Function {
if
strictcount(Parameter p |
exists(Context c | c = ParamNull(p) or c = ParamNotNull(p)) and
p = getOtherParameter(index)
p = this.getOtherParameter(index)
) = 1
then
exists(Parameter p | p = getOtherParameter(index) |
exists(Parameter p | p = this.getOtherParameter(index) |
result = ParamNull(p) or result = ParamNotNull(p)
)
else
@@ -424,8 +424,8 @@ class ConditionalInitializationCall extends FunctionCall {
/** Gets the argument passed for the given parameter to this call. */
Expr getArgumentForParameter(Parameter p) {
p = getTarget().getAParameter() and
result = getArgument(p.getIndex())
p = this.getTarget().getAParameter() and
result = this.getArgument(p.getIndex())
}
/**
@@ -442,7 +442,7 @@ class ConditionalInitializationCall extends FunctionCall {
context = ParamNotNull(otherP) or
context = ParamNull(otherP)
|
otherArg = getArgumentForParameter(otherP) and
otherArg = this.getArgumentForParameter(otherP) and
(otherArg instanceof AddressOfExpr implies context = ParamNotNull(otherP)) and
(otherArg.getType() instanceof ArrayType implies context = ParamNotNull(otherP)) and
(otherArg.getValue() = "0" implies context = ParamNull(otherP))
@@ -511,8 +511,8 @@ class ConditionalInitializationCall extends FunctionCall {
)
)
or
exists(ControlFlowNode mid | mid = uncheckedReaches(var) |
not mid = getStatusVariable().getAnAccess() and
exists(ControlFlowNode mid | mid = this.uncheckedReaches(var) |
not mid = this.getStatusVariable().getAnAccess() and
not mid = var.getAnAccess() and
not exists(VariableAccess write | result = write and write = var.getAnAccess() |
write = any(AssignExpr a).getLValue() or

View File

@@ -44,7 +44,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
// Find a call that conditionally initializes this variable
hasConditionalInitialization(f, call, this, initAccess, e) and
// Ignore cases where the variable is assigned prior to the call
not reaches(getAnAssignedValue(), initAccess) and
not reaches(this.getAnAssignedValue(), initAccess) and
// Ignore cases where the variable is assigned field-wise prior to the call.
not exists(FieldAccess fa |
exists(Assignment a |
@@ -56,7 +56,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
) and
// Ignore cases where the variable is assigned by a prior call to an initialization function
not exists(Call c |
getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
this.getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
reaches(c, initAccess)
) and
/*
@@ -64,7 +64,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
* the CFG, but should always be considered as initialized, so exclude them.
*/
not exists(getInitializer().getExpr())
not exists(this.getInitializer().getExpr())
}
/**
@@ -90,7 +90,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
// Variable associated with this particular call
call = initializingCall and
// Access is a meaningful read access
result = getAReadAccess() and
result = this.getAReadAccess() and
// Which occurs after the call
reaches(call, result) and
/*
@@ -124,7 +124,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
call = initializingCall and
initializingFunction = f and
e = evidence and
result = getAReadAccessAfterCall(initializingCall) and
result = this.getAReadAccessAfterCall(initializingCall) and
(
// Access is risky because status return code ignored completely
call instanceof ExprInVoidContext
@@ -148,7 +148,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
call = initializingCall and
initializingFunction = f and
e = evidence and
result = getAReadAccessAfterCall(initializingCall) and
result = this.getAReadAccessAfterCall(initializingCall) and
exists(LocalVariable status, Assignment a |
a.getRValue() = call and
call = status.getAnAssignedValue() and
@@ -184,7 +184,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
ConditionalInitializationFunction initializingFunction,
ConditionalInitializationCall initializingCall, Evidence evidence
) {
result = getARiskyAccessBeforeStatusCheck(initializingFunction, initializingCall, evidence) or
result = getARiskyAccessWithNoStatusCheck(initializingFunction, initializingCall, evidence)
result = this.getARiskyAccessBeforeStatusCheck(initializingFunction, initializingCall, evidence) or
result = this.getARiskyAccessWithNoStatusCheck(initializingFunction, initializingCall, evidence)
}
}

View File

@@ -31,15 +31,15 @@ abstract class SystemData extends Element {
*/
Expr getAnExprIndirect() {
// direct SystemData
result = getAnExpr() or
result = this.getAnExpr() or
// flow via global or member variable (conservative approximation)
result = getAnAffectedVar().getAnAccess() or
result = this.getAnAffectedVar().getAnAccess() or
// flow via stack variable
definitionUsePair(_, getAnExprIndirect(), result) or
useUsePair(_, getAnExprIndirect(), result) or
useUsePair(_, result, getAnExprIndirect()) or
definitionUsePair(_, this.getAnExprIndirect(), result) or
useUsePair(_, this.getAnExprIndirect(), result) or
useUsePair(_, result, this.getAnExprIndirect()) or
// flow from assigned value to assignment expression
result.(AssignExpr).getRValue() = getAnExprIndirect()
result.(AssignExpr).getRValue() = this.getAnExprIndirect()
}
/**

View File

@@ -67,16 +67,16 @@ class IFStream extends Type {
*/
class CinVariable extends NamespaceVariable {
CinVariable() {
getName() = ["cin", "wcin"] and
getNamespace().getName() = "std"
this.getName() = ["cin", "wcin"] and
this.getNamespace().getName() = "std"
}
}
/** A call to `std::operator>>`. */
class OperatorRShiftCall extends FunctionCall {
OperatorRShiftCall() {
getTarget().getNamespace().getName() = "std" and
getTarget().hasName("operator>>")
this.getTarget().getNamespace().getName() = "std" and
this.getTarget().hasName("operator>>")
}
/*
@@ -87,15 +87,15 @@ class OperatorRShiftCall extends FunctionCall {
*/
Expr getSource() {
if getTarget() instanceof MemberFunction
then result = getQualifier()
else result = getArgument(0)
if this.getTarget() instanceof MemberFunction
then result = this.getQualifier()
else result = this.getArgument(0)
}
Expr getDest() {
if getTarget() instanceof MemberFunction
then result = getArgument(0)
else result = getArgument(1)
if this.getTarget() instanceof MemberFunction
then result = this.getArgument(0)
else result = this.getArgument(1)
}
}
@@ -119,7 +119,7 @@ abstract class PotentiallyDangerousInput extends Expr {
* Gets the width restriction that applies to the input stream
* for this expression, if any.
*/
Expr getWidth() { result = getPreviousAccess().getWidthAfter() }
Expr getWidth() { result = this.getPreviousAccess().getWidthAfter() }
private Expr getWidthSetHere() {
exists(FunctionCall widthCall |
@@ -154,11 +154,11 @@ abstract class PotentiallyDangerousInput extends Expr {
* after this expression, if any.
*/
Expr getWidthAfter() {
result = getWidthSetHere()
result = this.getWidthSetHere()
or
not exists(getWidthSetHere()) and
not isWidthConsumedHere() and
result = getWidth()
not exists(this.getWidthSetHere()) and
not this.isWidthConsumedHere() and
result = this.getWidth()
}
}

View File

@@ -0,0 +1,5 @@
## 0.0.4
### New Queries
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.

View File

@@ -0,0 +1 @@
## 0.0.5

View File

@@ -0,0 +1,2 @@
---
lastReleaseVersion: 0.0.5

View File

@@ -21,9 +21,9 @@ predicate argumentMayBeRoot(Expr e) {
class SetuidLikeFunctionCall extends FunctionCall {
SetuidLikeFunctionCall() {
(getTarget().hasGlobalName("setuid") or getTarget().hasGlobalName("setresuid")) and
(this.getTarget().hasGlobalName("setuid") or this.getTarget().hasGlobalName("setresuid")) and
// setuid/setresuid with the root user are false positives.
not argumentMayBeRoot(getArgument(0))
not argumentMayBeRoot(this.getArgument(0))
}
}
@@ -44,7 +44,7 @@ class SetuidLikeWrapperCall extends FunctionCall {
class CallBeforeSetuidFunctionCall extends FunctionCall {
CallBeforeSetuidFunctionCall() {
getTarget()
this.getTarget()
.hasGlobalName([
"setgid", "setresgid",
// Compatibility may require skipping initgroups and setgroups return checks.
@@ -52,7 +52,7 @@ class CallBeforeSetuidFunctionCall extends FunctionCall {
"initgroups", "setgroups"
]) and
// setgid/setresgid/etc with the root group are false positives.
not argumentMayBeRoot(getArgument(0))
not argumentMayBeRoot(this.getArgument(0))
}
}

View File

@@ -24,7 +24,7 @@ class CallMayNotReturn extends FunctionCall {
not exists(this.(ControlFlowNode).getASuccessor())
or
// call to another function that may not return
exists(CallMayNotReturn exit | getTarget() = exit.getEnclosingFunction())
exists(CallMayNotReturn exit | this.getTarget() = exit.getEnclosingFunction())
}
}

View File

@@ -38,13 +38,7 @@ where
fc.getTargetType().(Class).getABaseClass+().hasGlobalOrStdName("exception") or
fc.getTargetType().(Class).getABaseClass+().hasGlobalOrStdName("CException")
) and
fc instanceof ExprInVoidContext and
not fc.isInMacroExpansion() and
not exists(ThrowExpr texp | fc.getEnclosingStmt() = texp.getEnclosingStmt()) and
not exists(FunctionCall fctmp | fctmp.getAnArgument() = fc) and
not fc instanceof ConstructorDirectInit and
not fc.getEnclosingStmt() instanceof DeclStmt and
not fc instanceof ConstructorDelegationInit and
not fc.getParent() instanceof Initializer and
not fc.getParent() instanceof AllocationExpr and
msg = "This object does not generate an exception."
msg = "Object creation of exception type on stack. Did you forget the throw keyword?"
select fc, msg

View File

@@ -118,7 +118,7 @@ private predicate exprReleases(Expr e, Expr released, string kind) {
}
class Resource extends MemberVariable {
Resource() { not isStatic() }
Resource() { not this.isStatic() }
// Check that an expr is somewhere in this class - does not have to be a constructor
predicate inSameClass(Expr e) {
@@ -129,7 +129,7 @@ class Resource extends MemberVariable {
f instanceof Destructor and f.getDeclaringType() = this.getDeclaringType()
or
exists(Function mid, FunctionCall fc |
calledFromDestructor(mid) and
this.calledFromDestructor(mid) and
fc.getEnclosingFunction() = mid and
fc.getTarget() = f and
f.getDeclaringType() = this.getDeclaringType()
@@ -137,7 +137,7 @@ class Resource extends MemberVariable {
}
predicate inDestructor(Expr e) {
exists(Function f | f = e.getEnclosingFunction() | calledFromDestructor(f))
exists(Function f | f = e.getEnclosingFunction() | this.calledFromDestructor(f))
}
predicate acquisitionWithRequiredKind(Assignment acquireAssign, string kind) {

View File

@@ -1,5 +1,6 @@
name: codeql/cpp-queries
version: 0.0.2
version: 0.0.5
groups: cpp
dependencies:
codeql/cpp-all: "*"
codeql/suite-helpers: "*"

View File

@@ -29,7 +29,8 @@ class CustomAddFunctionCall extends SimpleRangeAnalysisExpr, FunctionCall {
class SelfSub extends SimpleRangeAnalysisExpr, SubExpr {
SelfSub() {
getLeftOperand().(VariableAccess).getTarget() = getRightOperand().(VariableAccess).getTarget()
this.getLeftOperand().(VariableAccess).getTarget() =
this.getRightOperand().(VariableAccess).getTarget()
}
override float getLowerBounds() { result = 0 }

View File

@@ -1,3 +1,3 @@
| test.cpp:35:3:35:33 | call to runtime_error | This object does not generate an exception. |
| test.cpp:35:3:35:33 | call to runtime_error | Object creation of exception type on stack. Did you forget the throw keyword? |
| test.cpp:41:3:41:11 | call to funcTest1 | There is an exception in the function that requires your attention. |
| test.cpp:42:3:42:9 | call to DllMain | DllMain contains an exeption not wrapped in a try..catch block. |

View File

@@ -4,8 +4,8 @@ using SinkFunction = void (*)(int);
void notSink(int notSinkParam);
void callsSink(int sinkParam) { // $ ir-path=31:28 ir-path=32:31 ir-path=34:22
sink(sinkParam); // $ ir-sink=31:28 ir-sink=32:31 ir-sink=34:22 ast=31:28 ast=32:31 ast=34:22 MISSING: ast,ir=28
void callsSink(int sinkParam) { // $ ir-path=31:23 ir-path=32:26 ir-path=34:17
sink(sinkParam); // $ ast=31:28 ast=32:31 ast=34:22 ir-sink
}
struct {
@@ -25,7 +25,7 @@ void assignGlobals() {
};
void testStruct() {
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ ir MISSING: ast
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ MISSING: ir-path,ast
globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // clean
globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // $ ast ir-path
@@ -48,8 +48,8 @@ class D2 : public D1 {
class D3 : public D2 {
public:
void f(const char* p) override { // $ ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 ir-path=73:30
sink(p); // $ ir-sink=58:10 ir-sink=60:17 ir-sink=61:28 ir-sink=62:29 ir-sink=63:33 ast=58:10 ast=60:17 ast=61:28 ast=62:29 ast=63:33 SPURIOUS: ast=73:30 ir-sink=73:30
void f(const char* p) override { // $ ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 SPURIOUS: ir-path=73:30
sink(p); // $ ast=58:10 ast=60:17 ast=61:28 ast=62:29 ast=63:33 ir-sink SPURIOUS: ast=73:30
}
};

View File

@@ -23,11 +23,10 @@ class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
override predicate isSink(Element e) { isSinkArgument(e) }
}
predicate irTaint(Element source, Element sink, string tag) {
exists(TaintedWithPath::PathNode sinkNode, TaintedWithPath::PathNode predNode |
predicate irTaint(Element source, TaintedWithPath::PathNode predNode, string tag) {
exists(TaintedWithPath::PathNode sinkNode |
TaintedWithPath::taintedWithPath(source, _, _, sinkNode) and
predNode = getAPredecessor*(sinkNode) and
sink = getElementFromPathNode(predNode) and
// Make sure the path is actually reachable from this predecessor.
// Otherwise, we could pick `predNode` to be b when `source` is
// `source1` in this dataflow graph:
@@ -35,7 +34,7 @@ predicate irTaint(Element source, Element sink, string tag) {
// ^
// source2 ---> b --/
source = getElementFromPathNode(getAPredecessor*(predNode)) and
if sinkNode = predNode then tag = "ir-sink" else tag = "ir-path"
if predNode = sinkNode then tag = "ir-sink" else tag = "ir-path"
)
}
@@ -45,21 +44,25 @@ class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
override string getARelevantTag() { result = ["ir-path", "ir-sink"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Element source, Element tainted, int n |
irTaint(source, tainted, tag) and
n = strictcount(Element otherSource | irTaint(otherSource, tainted, _)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
exists(Element source, Element elem, TaintedWithPath::PathNode node, int n |
irTaint(source, node, tag) and
elem = getElementFromPathNode(node) and
n = count(int startline | getAPredecessor(node).hasLocationInfo(_, startline, _, _, _)) and
location = elem.getLocation() and
element = elem.toString()
|
// Zero predecessors means it's a source, and 1 predecessor means it has a unique predecessor.
// In either of these cases we leave out the location.
n = [0, 1] and value = ""
or
// If there is more than one predecessor for this node
// we specify the source location explicitly.
n > 1 and
exists(TaintedWithPath::PathNode pred | pred = getAPredecessor(node) |
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = tainted.getLocation() and
element = tainted.toString()
getElementFromPathNode(pred).getLocation().getStartLine().toString() + ":" +
getElementFromPathNode(pred).getLocation().getStartColumn()
)
)
}
}

View File

@@ -13,8 +13,8 @@ struct S {
}
};
void calls_sink_with_argv(const char* a) { // $ ir-path=96:26 ir-path=98:18
sink(a); // $ ast=96:26 ast=98:18 ir-sink=96:26 ir-sink=98:18
void calls_sink_with_argv(const char* a) { // $ ir-path=96:26 ir-path=102:26
sink(a); // $ ast=96:26 ast=98:18 ir-sink
}
extern int i;
@@ -27,7 +27,7 @@ public:
class DerivedCallsSink : public BaseWithPureVirtual {
public:
void f(const char* p) override { // $ ir-path
sink(p); // $ ir-sink ast=108:10 SPURIOUS: ast=111:10
sink(p); // $ ast=108:10 ir-sink SPURIOUS: ast=111:10
}
};
@@ -49,8 +49,8 @@ public:
};
class DerivesMultiple : public DerivedCallsSinkDiamond1, public DerivedDoesNotCallSinkDiamond2 {
void f(const char* p) override { // $ ir-path
DerivedCallsSinkDiamond1::f(p);
void f(const char* p) override { // $ ir-path=53:37 ir-path=115:11
DerivedCallsSinkDiamond1::f(p); // $ ir-path
}
};
@@ -58,7 +58,7 @@ template<typename T>
class CRTP {
public:
void f(const char* p) { // $ ir-path
static_cast<T*>(this)->g(p);
static_cast<T*>(this)->g(p); // $ ir-path
}
};
@@ -79,7 +79,7 @@ class Derived2 : public Derived1 {
class Derived3 : public Derived2 {
public:
void f(const char* p) override { // $ ir-path=124:19 ir-path=126:43 ir-path=128:44
sink(p); // $ ast,ir-sink=124:19 ast,ir-sink=126:43 ast,ir-sink=128:44
sink(p); // $ ast=124:19 ast=126:43 ast=128:44 ir-sink
}
};
@@ -97,11 +97,11 @@ int main(int argc, char *argv[]) {
char*** p = &argv; // $ ast,ir-path
sink(*p[0]); // $ ast,ir-sink
sink(*p[0]); // $ ast ir-sink=96:26 ir-sink=98:18
calls_sink_with_argv(*p[i]); // $ MISSING: ast,ir-path
calls_sink_with_argv(*p[i]); // $ ir-path=96:26 ir-path=98:18 MISSING:ast
sink(*(argv + 1)); // $ ast,ir-path ir-sink
sink(*(argv + 1)); // $ ast ir-path ir-sink
BaseWithPureVirtual* b = new DerivedCallsSink;

View File

@@ -190,9 +190,9 @@ void test_pointers1()
sink(ptr1); // $ ast MISSING: ir
sink(ptr2); // $ SPURIOUS: ast
sink(*ptr2); // $ ast MISSING: ir
sink(ptr3); // $ ast MISSING: ir
sink(ptr4); // $ SPURIOUS: ast
sink(*ptr4); // $ ast MISSING: ir
sink(ptr3); // $ ast,ir
sink(ptr4); // $ SPURIOUS: ast,ir
sink(*ptr4); // $ ast,ir
}
void test_pointers2()

View File

@@ -35,17 +35,17 @@ postWithInFlow
| BarrierGuard.cpp:60:3:60:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:8:20:8:29 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:3:22:6 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:8:22:20 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:8:22:20 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:9:22:20 | sourceArray1 [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:8:26:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:8:26:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:27:26:34 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:8:26:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:28:3:28:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:28:22:28:23 | m1 [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:8:30:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:8:30:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:27:30:34 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:8:30:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:34:19:34:41 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:34:19:34:41 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:39:16:39:21 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -77,55 +77,55 @@ postWithInFlow
| dispatch.cpp:29:29:29:34 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:8:31:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:8:31:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:16:31:24 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:8:31:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:8:32:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:8:32:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:16:32:24 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:8:32:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:3:33:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:3:33:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:11:33:16 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:3:33:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:8:35:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:8:35:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:16:35:25 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:8:35:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:8:36:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:8:36:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:16:36:25 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:8:36:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:3:37:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:3:37:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:11:37:17 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:3:37:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:15:39:23 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:15:40:23 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:10:41:15 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:15:43:24 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:15:44:24 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:10:45:16 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:51:3:51:22 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:8:55:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:8:55:19 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:22:55:30 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:8:55:19 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:8:56:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:8:56:19 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:22:56:30 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:8:56:19 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:58:8:58:23 | call to readGlobalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:58:8:58:23 | call to readGlobalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:58:28:58:36 | call to readGlobalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:3:60:14 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:18:60:29 | Call [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:18:60:29 | new [post update] | PostUpdateNode should not be the target of local flow. |
@@ -140,34 +140,34 @@ postWithInFlow
| dispatch.cpp:65:10:65:21 | new [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:3:69:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:3:69:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:8:69:13 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:3:69:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:7:73:12 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:77:3:77:19 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:77:21:77:34 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:77:21:77:34 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:3:78:21 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:23:78:39 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:23:78:39 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:23:78:39 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:24:78:37 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:80:8:80:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:3:81:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:3:81:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:6:81:11 | x [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:3:81:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:85:3:85:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:3:89:10 | bottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:3:89:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:3:89:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | (Middle *)... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | (Top *)... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | bottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:21:89:26 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | bottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:3:90:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:3:90:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:3:90:10 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:12:90:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:12:90:14 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:18:90:23 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:12:90:14 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:100:3:100:18 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:105:5:105:17 | maybeCallSink [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:113:30:113:38 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -176,11 +176,11 @@ postWithInFlow
| dispatch.cpp:127:31:127:36 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:10:129:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:10:129:15 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:18:129:25 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:10:129:15 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:17:130:24 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:148:3:148:3 | u [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:148:5:148:5 | f [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:168:3:168:4 | u2 [post update] | PostUpdateNode should not be the target of local flow. |
@@ -191,10 +191,10 @@ postWithInFlow
| example.c:24:9:24:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:24:20:24:20 | y [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:9:26:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:13:26:16 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:18:26:24 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:18:26:24 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:19:26:24 | coords [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:2:28:12 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:14:28:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:14:28:25 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:22:28:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:23:28:25 | pos [post update] | PostUpdateNode should not be the target of local flow. |
@@ -227,23 +227,23 @@ postWithInFlow
| lambdas.cpp:43:3:43:3 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:43:3:43:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:43:3:43:3 | c [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:3:45:3 | t [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:3:45:3 | u [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:3:45:3 | w [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:4:45:4 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:4:45:4 | t [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:4:45:4 | t [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:7:45:7 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:7:45:7 | u [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:7:45:7 | u [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:10:45:10 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:10:45:10 | w [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:10:45:10 | w [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:7 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:5:16:10 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:7 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
@@ -259,11 +259,11 @@ postWithInFlow
| ref.cpp:31:7:31:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:31:7:31:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:31:7:31:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:7:37:19 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
@@ -276,26 +276,26 @@ postWithInFlow
| ref.cpp:48:7:48:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:48:7:48:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:48:7:48:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:5:55:17 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:19:55:20 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:19:55:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:5:58:13 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:19:55:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:15:58:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:15:58:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:5:61:24 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:15:58:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:26:61:27 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:26:61:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:5:64:13 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:26:61:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:15:64:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:15:64:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:15:64:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:5:75:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:5:75:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:9:75:11 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:5:79:10 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:5:83:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:5:83:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:9:83:11 | val [post update] | PostUpdateNode should not be the target of local flow. |
@@ -311,11 +311,11 @@ postWithInFlow
| ref.cpp:96:7:96:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:96:7:96:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:96:11:96:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:7:102:19 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:7:104:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:7:104:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:11:104:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
@@ -328,18 +328,18 @@ postWithInFlow
| ref.cpp:115:7:115:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:115:7:115:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:115:11:115:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:5:122:17 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:19:122:20 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:19:122:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:5:125:13 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:19:122:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:15:125:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:15:125:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:5:128:24 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:15:125:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:26:128:27 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:26:128:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:5:131:13 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:26:128:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:15:131:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:15:131:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:15:131:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:6:7:6:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:8:3:8:4 | t2 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:12:5:12:6 | t2 [post update] | PostUpdateNode should not be the target of local flow. |
@@ -520,40 +520,40 @@ postWithInFlow
| test.cpp:374:5:374:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:374:5:374:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:383:7:383:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:3:384:8 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:10:384:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:10:384:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:10:384:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:11:384:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:389:7:389:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:390:8:390:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:3:391:8 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:10:391:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:10:391:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:10:391:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:11:391:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:3:400:8 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:10:400:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:10:400:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:10:400:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:11:400:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:406:8:406:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:3:407:8 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:10:407:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:10:407:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:10:407:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:11:407:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:3:417:14 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:16:417:20 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:16:417:20 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:3:423:18 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:16:417:20 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:20:423:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:20:423:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:21:423:25 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:3:429:18 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:20:429:24 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:20:429:24 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:3:436:16 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:20:429:24 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:18:436:23 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:18:436:23 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:19:436:23 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:3:442:16 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:18:442:22 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:18:442:22 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:18:442:22 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:453:7:453:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:456:7:456:9 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:458:7:458:9 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
@@ -561,12 +561,12 @@ postWithInFlow
| test.cpp:465:4:465:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:465:4:465:4 | p [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:469:7:469:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:3:470:19 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:21:470:22 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:21:470:22 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:22:470:22 | x [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:3:481:19 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:21:481:21 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:21:481:30 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:21:481:30 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:24:481:30 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:24:481:30 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:482:8:482:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,28 @@
| A.cpp:25:13:25:13 | c | AST only |
| A.cpp:27:28:27:28 | c | AST only |
| A.cpp:31:14:31:21 | new | IR only |
| A.cpp:40:8:40:13 | 0 | IR only |
| A.cpp:41:8:41:13 | new | IR only |
| A.cpp:40:15:40:21 | 0 | IR only |
| A.cpp:41:15:41:21 | new | IR only |
| A.cpp:41:15:41:21 | new | IR only |
| A.cpp:47:12:47:18 | new | IR only |
| A.cpp:54:12:54:18 | new | IR only |
| A.cpp:55:8:55:10 | new | IR only |
| A.cpp:55:12:55:19 | new | IR only |
| A.cpp:55:12:55:19 | new | IR only |
| A.cpp:57:11:57:24 | new | IR only |
| A.cpp:57:11:57:24 | new | IR only |
| A.cpp:57:17:57:23 | new | IR only |
| A.cpp:57:28:57:30 | new | IR only |
| A.cpp:57:17:57:23 | new | IR only |
| A.cpp:62:13:62:19 | new | IR only |
| A.cpp:64:10:64:15 | new | IR only |
| A.cpp:64:21:64:28 | new | IR only |
| A.cpp:64:21:64:28 | new | IR only |
| A.cpp:71:13:71:19 | new | IR only |
| A.cpp:73:10:73:19 | new | IR only |
| A.cpp:73:25:73:32 | new | IR only |
| A.cpp:73:25:73:32 | new | IR only |
| A.cpp:89:15:89:21 | new | IR only |
| A.cpp:99:14:99:21 | new | IR only |
| A.cpp:100:9:100:9 | a | AST only |
| A.cpp:116:12:116:19 | new | IR only |
| A.cpp:126:8:126:10 | new | IR only |
| A.cpp:126:12:126:18 | new | IR only |
| A.cpp:126:12:126:18 | new | IR only |
| A.cpp:130:12:130:18 | new | IR only |
| A.cpp:142:10:142:10 | c | AST only |
@@ -33,57 +33,57 @@
| A.cpp:151:12:151:24 | new | IR only |
| A.cpp:159:12:159:18 | new | IR only |
| A.cpp:160:18:160:60 | new | IR only |
| A.cpp:160:18:160:60 | new | IR only |
| A.cpp:160:32:160:59 | 0 | IR only |
| A.cpp:160:32:160:59 | 0 | IR only |
| A.cpp:160:32:160:59 | new | IR only |
| A.cpp:161:18:161:40 | 0 | IR only |
| A.cpp:160:32:160:59 | new | IR only |
| A.cpp:160:43:160:49 | 0 | IR only |
| A.cpp:160:52:160:58 | 0 | IR only |
| A.cpp:161:18:161:40 | new | IR only |
| A.cpp:162:18:162:40 | 0 | IR only |
| A.cpp:161:29:161:35 | 0 | IR only |
| A.cpp:162:18:162:40 | new | IR only |
| A.cpp:162:29:162:35 | 0 | IR only |
| A.cpp:183:7:183:10 | head | AST only |
| A.cpp:184:13:184:16 | next | AST only |
| B.cpp:7:16:7:35 | 0 | IR only |
| B.cpp:7:16:7:35 | new | IR only |
| B.cpp:7:28:7:34 | 0 | IR only |
| B.cpp:8:16:8:27 | new | IR only |
| B.cpp:16:16:16:38 | 0 | IR only |
| B.cpp:16:16:16:38 | new | IR only |
| B.cpp:16:28:16:34 | 0 | IR only |
| B.cpp:17:16:17:27 | new | IR only |
| B.cpp:35:13:35:17 | elem1 | AST only |
| B.cpp:36:13:36:17 | elem2 | AST only |
| B.cpp:46:13:46:16 | box1 | AST only |
| C.cpp:18:12:18:18 | new | IR only |
| C.cpp:24:11:24:12 | s3 | AST only |
| C.cpp:30:5:30:8 | s2 | IR only |
| C.cpp:30:10:30:11 | s2 | IR only |
| C.cpp:30:10:30:11 | this | IR only |
| C.cpp:32:5:32:8 | s4 | IR only |
| C.cpp:32:10:32:11 | s4 | IR only |
| D.cpp:9:21:9:24 | elem | AST only |
| D.cpp:11:29:11:32 | elem | AST only |
| D.cpp:16:21:16:23 | box | AST only |
| D.cpp:18:29:18:31 | box | AST only |
| D.cpp:29:15:29:41 | new | IR only |
| D.cpp:29:15:29:41 | new | IR only |
| D.cpp:29:24:29:40 | 0 | IR only |
| D.cpp:29:24:29:40 | new | IR only |
| D.cpp:29:24:29:40 | new | IR only |
| D.cpp:29:33:29:39 | 0 | IR only |
| D.cpp:30:13:30:16 | elem | AST only |
| D.cpp:36:15:36:41 | new | IR only |
| D.cpp:36:15:36:41 | new | IR only |
| D.cpp:36:24:36:40 | 0 | IR only |
| D.cpp:36:24:36:40 | new | IR only |
| D.cpp:36:24:36:40 | new | IR only |
| D.cpp:36:33:36:39 | 0 | IR only |
| D.cpp:43:15:43:41 | new | IR only |
| D.cpp:43:15:43:41 | new | IR only |
| D.cpp:43:24:43:40 | 0 | IR only |
| D.cpp:43:24:43:40 | new | IR only |
| D.cpp:43:24:43:40 | new | IR only |
| D.cpp:43:33:43:39 | 0 | IR only |
| D.cpp:44:19:44:22 | elem | AST only |
| D.cpp:50:15:50:41 | new | IR only |
| D.cpp:50:15:50:41 | new | IR only |
| D.cpp:50:24:50:40 | 0 | IR only |
| D.cpp:50:24:50:40 | new | IR only |
| D.cpp:50:24:50:40 | new | IR only |
| D.cpp:50:33:50:39 | 0 | IR only |
| D.cpp:57:5:57:12 | boxfield | AST only |
| D.cpp:57:16:57:42 | new | IR only |
| D.cpp:57:16:57:42 | new | IR only |
| D.cpp:57:25:57:41 | 0 | IR only |
| D.cpp:57:25:57:41 | new | IR only |
| D.cpp:57:25:57:41 | new | IR only |
| D.cpp:57:34:57:40 | 0 | IR only |
| D.cpp:58:20:58:23 | elem | AST only |
| aliasing.cpp:9:6:9:7 | m1 | AST only |
| aliasing.cpp:13:5:13:6 | m1 | AST only |
@@ -100,13 +100,13 @@
| aliasing.cpp:98:5:98:6 | m1 | AST only |
| aliasing.cpp:106:3:106:5 | * ... | AST only |
| arrays.cpp:6:3:6:8 | access to array | AST only |
| arrays.cpp:7:3:7:6 | access to array | IR only |
| arrays.cpp:8:3:8:6 | access to array | IR only |
| arrays.cpp:9:3:9:6 | * ... | IR only |
| arrays.cpp:10:3:10:6 | * ... | IR only |
| arrays.cpp:7:8:7:13 | access to array | IR only |
| arrays.cpp:8:8:8:13 | access to array | IR only |
| arrays.cpp:9:8:9:11 | * ... | IR only |
| arrays.cpp:10:8:10:15 | * ... | IR only |
| arrays.cpp:15:3:15:10 | * ... | AST only |
| arrays.cpp:16:3:16:6 | access to array | IR only |
| arrays.cpp:17:3:17:6 | access to array | IR only |
| arrays.cpp:16:8:16:13 | access to array | IR only |
| arrays.cpp:17:8:17:13 | access to array | IR only |
| arrays.cpp:36:19:36:22 | data | AST only |
| arrays.cpp:42:22:42:25 | data | AST only |
| arrays.cpp:48:22:48:25 | data | AST only |

View File

@@ -12,7 +12,7 @@ struct Outer {
};
void absink(struct AB *ab) {
sink(ab->a); //$ ast,ir=20:20 ast,ir=27:7 ast=40:20 MISSING: ir
sink(ab->a); //$ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
sink(ab->b); // no flow
}
@@ -30,7 +30,7 @@ int struct_init(void) {
sink(outer.nestedAB.a); //$ ast,ir
sink(outer.nestedAB.b); // no flow
sink(outer.pointerAB->a); //$ ast MISSING: ir
sink(outer.pointerAB->a); //$ ast,ir
sink(outer.pointerAB->b); // no flow
absink(&outer.nestedAB);

View File

@@ -21,9 +21,9 @@ void test_unique_ptr_struct() {
std::unique_ptr<A> p1(new A{source(), 0});
std::unique_ptr<A> p2 = std::make_unique<A>(source(), 0);
sink(p1->x); // $ ir MISSING: ast
sink(p1->x); // $ MISSING: ast,ir
sink(p1->y);
sink(p2->x); // $ ir=22:46 MISSING: ast
sink(p2->x); // $ MISSING: ast,ir=22:46
sink(p2->y);
}

View File

@@ -126,15 +126,15 @@ void pointer_test() {
*p2 = source();
sink(*p1); // $ ast MISSING: ir
sink(*p1); // $ ast,ir
sink(*p2); // $ ast,ir
sink(*p3);
p3 = &t1;
sink(*p3); // $ ast MISSING: ir
sink(*p3); // $ ast,ir
*p3 = 0;
sink(*p3); // $ SPURIOUS: ast
sink(*p3); // $ SPURIOUS: ast,ir
}
// --- return values ---

View File

@@ -1,10 +1,15 @@
private import cpp
/**
* Holds if the specified location is in standard headers.
*/
predicate locationIsInStandardHeaders(Location loc) {
loc.getFile().getAbsolutePath().regexpMatch(".*/include/[^/]+")
}
/**
* Holds if the AST or IR for the specified function should be printed in the test output.
*
* This predicate excludes functions defined in standard headers.
*/
predicate shouldDumpFunction(Function func) {
not func.getLocation().getFile().getAbsolutePath().regexpMatch(".*/include/[^/]+")
}
predicate shouldDumpFunction(Function func) { not locationIsInStandardHeaders(func.getLocation()) }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
private import cpp
private import semmle.code.cpp.ir.IR
private import PrintConfig
from Operand a
where not locationIsInStandardHeaders(a.getLocation())
select a, a.getDumpString()

View File

@@ -1474,7 +1474,7 @@ reverseRead
argHasPostUpdate
postWithInFlow
| FunctionTryStmt.cpp:2:3:2:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| VacuousDestructorCall.cpp:10:3:10:16 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| VacuousDestructorCall.cpp:10:21:10:22 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| VacuousDestructorCall.cpp:10:21:10:22 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| VacuousDestructorCall.cpp:10:22:10:22 | i [post update] | PostUpdateNode should not be the target of local flow. |
| abortingfunctions.cpp:49:5:49:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -1497,7 +1497,7 @@ postWithInFlow
| bad_asts.cpp:10:7:10:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:15:10:15:12 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:16:5:16:5 | s [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:16:7:16:23 | s [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:16:5:16:5 | s [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:27:11:27:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| break_labels.c:3:9:3:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| break_labels.c:5:9:5:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -1520,35 +1520,35 @@ postWithInFlow
| builtin.c:22:3:22:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:29:5:29:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:34:3:34:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:34:10:34:20 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:34:22:34:31 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:34:22:34:31 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:34:22:34:31 | (volatile void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:34:23:34:31 | staticint [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:39:3:39:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:39:10:39:23 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:39:36:39:45 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:39:36:39:45 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:39:37:39:45 | carry_out [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:43:3:43:24 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:43:40:43:49 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:43:40:43:49 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:43:41:43:49 | staticint [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:45:3:45:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:48:2:48:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:51:3:51:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:51:10:51:27 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:51:29:51:38 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:51:29:51:38 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:51:30:51:38 | staticint [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:54:3:54:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:54:10:54:26 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:54:28:54:38 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:54:28:54:38 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:54:29:54:38 | atomic_int [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.c:56:3:56:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:5:5:5:34 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:10:10:10:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:10:14:10:22 | i [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:10:24:10:24 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:10:24:10:24 | i [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:10:24:10:24 | i [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:14:11:14:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:15:5:15:29 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:15:31:15:35 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:15:31:15:35 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:15:32:15:35 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| builtin.cpp:15:33:15:35 | ptr [post update] | PostUpdateNode should not be the target of local flow. |
@@ -1559,18 +1559,18 @@ postWithInFlow
| condition_decls.cpp:3:13:3:22 | Call [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:3:13:3:22 | new [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:9:5:9:18 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:16:6:16:20 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:16:6:16:20 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:16:19:16:20 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:26:10:26:24 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:26:10:26:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:26:23:26:24 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:41:9:41:23 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:41:9:41:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:41:22:41:23 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:48:16:48:19 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:48:16:48:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:48:22:48:24 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:48:27:48:31 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:48:27:48:31 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:48:34:48:36 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:48:39:48:53 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:48:39:48:53 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| condition_decls.cpp:48:52:48:53 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| conditional_destructors.cpp:6:13:6:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| conditional_destructors.cpp:6:13:6:15 | val [post update] | PostUpdateNode should not be the target of local flow. |
| conditional_destructors.cpp:10:9:10:32 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -1594,8 +1594,8 @@ postWithInFlow
| conditional_destructors.cpp:42:18:42:22 | call to C2 [post update] | PostUpdateNode should not be the target of local flow. |
| conditional_destructors.cpp:42:18:42:22 | temporary object [post update] | PostUpdateNode should not be the target of local flow. |
| constmemberaccess.cpp:9:2:9:2 | i [post update] | PostUpdateNode should not be the target of local flow. |
| constructorinitializer.cpp:8:4:8:4 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| constructorinitializer.cpp:8:4:8:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| constructorinitializer.cpp:8:6:8:18 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:6:5:6:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:6:5:6:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:6:5:6:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -1650,13 +1650,13 @@ postWithInFlow
| cpp17.cpp:15:5:15:45 | Call [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:15:5:15:45 | new [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:15:5:15:45 | new [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:5:19:8 | 1 [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:5:19:8 | 2 [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:5:19:8 | p [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:10:19:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:10:19:10 | p [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:10:19:10 | p [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:13:19:13 | 1 [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:13:19:13 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:13:19:13 | temporary object [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:16:19:16 | 2 [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:16:19:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| cpp17.cpp:19:16:19:16 | temporary object [post update] | PostUpdateNode should not be the target of local flow. |
| defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -1982,20 +1982,20 @@ postWithInFlow
| ir.cpp:579:10:579:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:579:16:579:21 | PointerAdd [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:579:16:579:21 | PointerAdd [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:585:5:585:18 | string [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:585:32:585:39 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:585:32:585:39 | string [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:585:32:585:39 | string [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:591:11:591:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:592:5:592:7 | pfn [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:593:5:593:7 | pfn [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:594:5:594:7 | pfn [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:616:12:616:13 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:616:12:616:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:617:12:617:13 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:617:12:617:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:617:15:617:22 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:618:12:618:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:619:12:619:13 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:619:12:619:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:619:16:619:30 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:631:9:631:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:635:9:635:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:639:9:639:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2011,11 +2011,11 @@ postWithInFlow
| ir.cpp:649:9:649:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:653:9:653:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:653:9:653:12 | this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:653:15:653:36 | this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:653:9:653:12 | this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:654:10:654:14 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:654:10:654:14 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:654:11:654:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:654:11:654:14 | this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:654:17:654:38 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:655:9:655:30 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:655:9:655:30 | this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:655:9:655:30 | this [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2042,7 +2042,7 @@ postWithInFlow
| ir.cpp:716:5:716:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:716:12:716:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:721:3:721:54 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:721:10:721:39 | 0 [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:721:41:721:47 | 0 [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:721:41:721:47 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:726:9:726:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:728:7:728:28 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2110,13 +2110,13 @@ postWithInFlow
| ir.cpp:805:11:805:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:806:12:806:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:808:3:808:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:808:5:808:5 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:808:3:808:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:809:3:809:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:809:3:809:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:809:5:809:5 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:809:7:809:13 | call to Base [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:809:7:809:13 | temporary object [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:810:3:810:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:810:5:810:5 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:810:3:810:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:810:7:810:26 | call to Base [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:810:7:810:26 | temporary object [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:811:3:811:4 | pb [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2124,20 +2124,20 @@ postWithInFlow
| ir.cpp:813:3:813:4 | pb [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:814:3:814:4 | pb [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:816:3:816:3 | m [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:816:5:816:5 | m [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:816:3:816:3 | m [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:817:3:817:3 | m [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:817:3:817:3 | m [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:817:5:817:5 | m [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:818:3:818:4 | pm [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:819:3:819:4 | pm [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:820:3:820:4 | pm [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:822:3:822:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:822:5:822:5 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:822:3:822:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:823:3:823:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:823:3:823:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:823:5:823:5 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:823:7:823:13 | call to Base [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:823:7:823:13 | temporary object [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:824:3:824:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:824:5:824:5 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:824:3:824:3 | b [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:824:7:824:26 | call to Base [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:824:7:824:26 | temporary object [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:825:3:825:4 | pb [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2145,9 +2145,9 @@ postWithInFlow
| ir.cpp:827:3:827:4 | pb [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:828:3:828:4 | pb [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:830:3:830:3 | d [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:830:5:830:5 | d [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:830:3:830:3 | d [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:831:3:831:3 | d [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:831:3:831:3 | d [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:831:5:831:5 | d [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:832:3:832:4 | pd [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:833:3:833:4 | pd [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:834:3:834:4 | pd [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2170,8 +2170,8 @@ postWithInFlow
| ir.cpp:861:23:861:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:863:9:863:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:864:15:864:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:867:1:867:14 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:867:1:867:14 | this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:868:3:868:12 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:873:15:873:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:874:3:874:3 | p [post update] | PostUpdateNode should not be the target of local flow. |
| ir.cpp:875:3:875:3 | p [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2293,23 +2293,23 @@ postWithInFlow
| misc.c:229:7:229:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:230:2:230:3 | p1 [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:231:2:231:40 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| modeled-functions.cpp:6:3:6:8 | 0 [post update] | PostUpdateNode should not be the target of local flow. |
| modeled-functions.cpp:6:3:6:8 | 0 [post update] | PostUpdateNode should not be the target of local flow. |
| modeled-functions.cpp:6:19:6:19 | 0 [post update] | PostUpdateNode should not be the target of local flow. |
| modeled-functions.cpp:6:19:6:19 | (char *)... [post update] | PostUpdateNode should not be the target of local flow. |
| modeled-functions.cpp:6:22:6:22 | 0 [post update] | PostUpdateNode should not be the target of local flow. |
| modeled-functions.cpp:6:22:6:22 | (unsigned long *)... [post update] | PostUpdateNode should not be the target of local flow. |
| ms_assume.cpp:13:8:13:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ms_assume.cpp:14:8:14:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ms_assume.cpp:28:3:28:8 | result [post update] | PostUpdateNode should not be the target of local flow. |
| ms_assume.cpp:28:12:28:16 | buffer [post update] | PostUpdateNode should not be the target of local flow. |
| ms_assume.cpp:28:18:28:23 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| ms_assume.cpp:28:18:28:23 | buffer [post update] | PostUpdateNode should not be the target of local flow. |
| ms_assume.cpp:28:18:28:23 | buffer [post update] | PostUpdateNode should not be the target of local flow. |
| ms_assume.cpp:34:1:34:1 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ms_try_mix.cpp:11:7:11:10 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ms_try_mix.cpp:11:7:11:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ms_try_mix.cpp:11:12:11:15 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ms_try_mix.cpp:28:7:28:10 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ms_try_mix.cpp:28:7:28:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ms_try_mix.cpp:28:12:28:15 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ms_try_mix.cpp:48:5:48:8 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| ms_try_mix.cpp:48:5:48:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ms_try_mix.cpp:48:10:48:13 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| newexpr.cpp:8:2:8:20 | Call [post update] | PostUpdateNode should not be the target of local flow. |
| newexpr.cpp:8:2:8:20 | new [post update] | PostUpdateNode should not be the target of local flow. |
| newexpr.cpp:8:2:8:20 | new [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2321,21 +2321,21 @@ postWithInFlow
| ops.cpp:26:31:26:53 | Call [post update] | PostUpdateNode should not be the target of local flow. |
| ops.cpp:26:31:26:53 | new [post update] | PostUpdateNode should not be the target of local flow. |
| ops.cpp:26:31:26:53 | new [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:8:5:8:10 | Got %d\n [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:8:12:8:21 | (char *)... [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:8:12:8:21 | Got %d\n [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:8:12:8:21 | Got %d\n [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:8:12:8:21 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:25:5:25:8 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:25:5:25:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:27:3:27:6 | my_c [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:27:8:27:13 | my_c [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:27:3:27:6 | my_c [post update] | PostUpdateNode should not be the target of local flow. |
| parameterinitializer.cpp:30:5:30:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| pointer_to_member.cpp:23:6:23:8 | obj [post update] | PostUpdateNode should not be the target of local flow. |
| pointer_to_member.cpp:23:10:23:14 | obj [post update] | PostUpdateNode should not be the target of local flow. |
| pointer_to_member.cpp:23:6:23:8 | obj [post update] | PostUpdateNode should not be the target of local flow. |
| pointer_to_member.cpp:26:5:26:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| pointer_to_member.cpp:27:5:27:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| pointer_to_member.cpp:27:12:27:14 | obj [post update] | PostUpdateNode should not be the target of local flow. |
| pointer_to_member.cpp:27:16:27:20 | obj [post update] | PostUpdateNode should not be the target of local flow. |
| pointer_to_member.cpp:27:12:27:14 | obj [post update] | PostUpdateNode should not be the target of local flow. |
| pointer_to_member.cpp:29:5:29:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| pruning.c:69:9:69:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| pruning.c:78:9:78:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2585,9 +2585,9 @@ postWithInFlow
| static_init_templates.cpp:3:2:3:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| static_init_templates.cpp:3:2:3:4 | ref [post update] | PostUpdateNode should not be the target of local flow. |
| static_init_templates.cpp:18:7:18:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| static_init_templates.cpp:20:2:20:10 | a [post update] | PostUpdateNode should not be the target of local flow. |
| static_init_templates.cpp:20:12:20:12 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| static_init_templates.cpp:20:12:20:12 | a [post update] | PostUpdateNode should not be the target of local flow. |
| static_init_templates.cpp:20:12:20:12 | a [post update] | PostUpdateNode should not be the target of local flow. |
| static_init_templates.cpp:21:2:21:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| static_init_templates.cpp:21:2:21:4 | val [post update] | PostUpdateNode should not be the target of local flow. |
| static_init_templates.cpp:22:2:22:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2629,8 +2629,8 @@ postWithInFlow
| staticlocals.cpp:26:19:26:21 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| staticlocals.cpp:29:14:29:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| staticlocals.cpp:29:14:29:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| stmt_expr.cpp:13:16:13:16 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| stmt_expr.cpp:13:16:13:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| stmt_expr.cpp:13:18:13:19 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| stmt_expr.cpp:27:5:27:7 | ptr [post update] | PostUpdateNode should not be the target of local flow. |
| stream_it.cpp:4:16:4:30 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| stream_it.cpp:5:14:5:28 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2644,9 +2644,9 @@ postWithInFlow
| stream_it.cpp:11:16:11:16 | (__range) [post update] | PostUpdateNode should not be the target of local flow. |
| stream_it.cpp:11:16:11:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| stream_it.cpp:11:16:11:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| stream_it.cpp:19:3:19:11 | xs [post update] | PostUpdateNode should not be the target of local flow. |
| stream_it.cpp:19:13:19:14 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| stream_it.cpp:19:13:19:14 | xs [post update] | PostUpdateNode should not be the target of local flow. |
| stream_it.cpp:19:13:19:14 | xs [post update] | PostUpdateNode should not be the target of local flow. |
| stream_it.cpp:20:3:20:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| subscriptexpr.c:4:2:4:2 | i [post update] | PostUpdateNode should not be the target of local flow. |
| switchbody.c:5:11:5:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -136,7 +136,7 @@ useNotDominatedByDefinition
| VacuousDestructorCall.cpp:2:29:2:29 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) |
| misc.c:219:47:219:48 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) |
| static_init_templates.cpp:15:1:15:18 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | static_init_templates.cpp:15:1:15:18 | void MyClass::MyClass() | void MyClass::MyClass() |
| try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) |
| try_catch.cpp:21:9:21:9 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) |
| vla.c:3:27:3:30 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) |
switchInstructionWithoutDefaultEdge
notMarkedAsConflated

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-tests
version: 0.0.2
groups: [cpp, test]
dependencies:
codeql/cpp-all: "*"
codeql/cpp-queries: "*"

View File

@@ -12,17 +12,17 @@ edges
| search.c:22:24:22:28 | query | search.c:23:39:23:43 | query |
| search.c:22:24:22:28 | query | search.c:23:39:23:43 | query |
| search.c:22:24:22:28 | query | search.c:23:39:23:43 | query indirection |
| search.c:51:21:51:26 | call to getenv | search.c:55:5:55:15 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:55:5:55:15 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:55:17:55:25 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:55:17:55:25 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:55:17:55:25 | raw_query indirection |
| search.c:51:21:51:26 | call to getenv | search.c:55:17:55:25 | raw_query indirection |
| search.c:51:21:51:26 | call to getenv | search.c:57:5:57:15 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:57:5:57:15 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:57:17:57:25 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:57:17:57:25 | raw_query |
| search.c:51:21:51:26 | call to getenv | search.c:57:17:57:25 | raw_query indirection |
| search.c:51:21:51:26 | call to getenv | search.c:57:17:57:25 | raw_query indirection |
| search.c:55:5:55:15 | raw_query | search.c:14:24:14:28 | query |
| search.c:55:17:55:25 | raw_query | search.c:14:24:14:28 | query |
| search.c:55:17:55:25 | raw_query indirection | search.c:14:24:14:28 | *query |
| search.c:57:5:57:15 | raw_query | search.c:22:24:22:28 | query |
| search.c:57:17:57:25 | raw_query | search.c:22:24:22:28 | query |
| search.c:57:17:57:25 | raw_query indirection | search.c:22:24:22:28 | *query |
subpaths
nodes
@@ -44,9 +44,9 @@ nodes
| search.c:23:39:23:43 | query indirection | semmle.label | query indirection |
| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv |
| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv |
| search.c:55:5:55:15 | raw_query | semmle.label | raw_query |
| search.c:55:17:55:25 | raw_query | semmle.label | raw_query |
| search.c:55:17:55:25 | raw_query indirection | semmle.label | raw_query indirection |
| search.c:57:5:57:15 | raw_query | semmle.label | raw_query |
| search.c:57:17:57:25 | raw_query | semmle.label | raw_query |
| search.c:57:17:57:25 | raw_query indirection | semmle.label | raw_query indirection |
#select
| search.c:17:8:17:12 | query | search.c:51:21:51:26 | call to getenv | search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:51:21:51:26 | call to getenv | this query data |

View File

@@ -6,11 +6,11 @@ edges
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data indirection |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:17:73:22 | data |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:17:73:22 | data |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
| test.cpp:73:17:73:22 | data | test.cpp:37:73:37:76 | data |
| test.cpp:73:24:73:27 | data | test.cpp:37:73:37:76 | data |
| test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | *data |
subpaths
nodes
@@ -25,7 +25,7 @@ nodes
| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
| test.cpp:73:17:73:22 | data | semmle.label | data |
| test.cpp:73:24:73:27 | data | semmle.label | data |
| test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection |
#select
| test.cpp:43:32:43:35 | data | test.cpp:64:30:64:35 | call to getenv | test.cpp:43:32:43:35 | data | The value of this argument may come from $@ and is being passed to LoadLibraryA | test.cpp:64:30:64:35 | call to getenv | call to getenv |

Some files were not shown because too many files have changed in this diff Show More