Compare commits

..

744 Commits

Author SHA1 Message Date
Dave Bartolomeo
712d71856b Merge pull request #7401 from github/release-prep/2.7.4
Release preparation for version 2.7.4
2021-12-14 16:42:33 -05:00
github-actions[bot]
59da2cdf69 Release preparation for version 2.7.4 2021-12-14 21:35:09 +00:00
Dave Bartolomeo
6664a3814a Merge pull request #7398 from github/dbartol/fix-change-notes
Fix change notes
2021-12-14 13:53:08 -05:00
Dave Bartolomeo
fa40d59332 Move older change notes to old-change-notes
Now that change notes are per-package, new change notes should be created in the `change-notes` folder under the affected pack (e.g., `cpp/ql/src/change-notes` for C++ query change notes. I've moved all of the change note files that were added before we started publishing them in packs to an `old-change-notes` directory under each language, to reduce the temptation to add new change notes there.

I'm working on a document to describe how and when to create change notes for packs separately.
2021-12-14 12:35:04 -05:00
Dave Bartolomeo
a62f181d42 Move new change notes to appropriate packs 2021-12-14 12:05:15 -05:00
Erik Krogh Kristensen
de4458346f Merge pull request #7344 from SZFsir/main
JS: Improve inter-procedural type inference for FunctionExpr
2021-12-13 21:58:53 +01:00
Nick Rolfe
dc27089714 Merge pull request #7375 from github/nickrolfe/cargo_update
Ruby: update crate versions
2021-12-13 18:16:29 +00:00
Dave Bartolomeo
7732c0885f Merge pull request #7374 from aeisenberg/aesenberg/upgrades-semver
Fix semver for upgrades references
2021-12-13 13:06:59 -05:00
Andrew Eisenberg
0669ef505e Fix semver for upgrades references
Ensure the version range is flexible enough to handle
future version changes.
2021-12-13 09:03:33 -08:00
Aditya Sharad
372f099850 Merge pull request #7323 from adityasharad/atm/perf-debugging-std-lib
JS: Performance improvements to libraries using regex matching
2021-12-13 08:53:11 -08:00
Nick Rolfe
b18f7a9bd7 Ruby: update crate versions 2021-12-13 15:37:35 +00:00
Michael Nebel
c0b61d7f73 Merge pull request #7370 from michaelnebel/csharp-mad-textreader
C#: Flow summaries for virtual members in abstract classes should also apply to overrides.
2021-12-13 15:00:54 +01:00
Alex Ford
124aac23c6 Merge pull request #7371 from github/ruby/comment-new-syntax
Ruby: use Ruby object instantiation syntax in a comment
2021-12-13 13:23:03 +00:00
Alex Ford
4ae92667e1 Ruby: use Ruby object instantiation syntax in a comment 2021-12-13 12:54:45 +00:00
Michael Nebel
ba23393c0d C#: Update test as we now also implicitly gets flow summary for StreamReader. 2021-12-13 13:51:53 +01:00
Michael Nebel
a6eba04793 C#: Convert System.IO.TextReader flow to CSV format. 2021-12-13 13:51:18 +01:00
Michael Nebel
88bb8a2704 C#: Update flow summaries test cases. 2021-12-13 13:14:49 +01:00
Michael Nebel
d699ca9aa8 C#: Flow summaries should also apply for overides or virtual members in abstract classes. 2021-12-13 13:09:40 +01:00
Michael Nebel
7ff2ee695d Merge pull request #7348 from michaelnebel/csharp-mad-as-csv-json
C#: Convert flow summaries for JSon.NET
2021-12-13 11:57:55 +01:00
JrXnm
efc9e67ec2 Update javascript/ql/lib/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll
Fix multiple declare may mismatch issue

Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2021-12-13 18:36:06 +08:00
JrXnm
fad95d8935 Update javascript/ql/lib/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll
Commit coding style suggestion

Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2021-12-13 18:32:11 +08:00
Michael Nebel
f32d464c0f C#: Ensure bi-directional import for External flow. 2021-12-13 10:50:49 +01:00
Michael Nebel
327cf444f4 C#: Convert Newtonsoft.JSon.Linq.JObject and Newtonsoft.JSon.Linq.JToken flow to CSV format. 2021-12-13 10:50:49 +01:00
Michael Nebel
f3c0eadbce C#: Fix the existing callableFlow for JObject to target the inherited ToString methods from JToken. 2021-12-13 10:50:49 +01:00
Michael Nebel
58f36e4b31 C#: Convert NewtonSoft.Json.JSonSerializer flow to CSV format. 2021-12-13 10:50:49 +01:00
Michael Nebel
90e49508a3 C#: Convert Newtonsoft.Json.JsonConvert flow to CSV format. 2021-12-13 10:50:48 +01:00
Michael Nebel
a4bea05fa7 Merge pull request #7342 from michaelnebel/csharp-mad-as-csv3
C#: More Flow summaries in CSV format.
2021-12-13 10:32:28 +01:00
Michael Nebel
be1e75471e C#: Ensure bi-directional import for external flow. 2021-12-13 09:23:11 +01:00
Michael Nebel
1cab177f8a C#: Convert System.Web.HttpUtility flow to CSV format. 2021-12-13 09:19:41 +01:00
Michael Nebel
0e0c3e3937 C#: Convert System.Web.HttpServerUtility flow to CSV format. 2021-12-13 09:19:41 +01:00
Michael Nebel
6301e726ee C#: Update HttpServerUtility stub with HtmlEncode method and update flow summaries test. 2021-12-13 09:19:41 +01:00
Michael Nebel
1cd37dddf5 C#: Convert System.Net.WebUtility flow to CSV format. 2021-12-13 09:19:41 +01:00
Michael Nebel
07a4f5f748 C#: Update FlowSummaries test as the bogus flow summaries for the KeyValuePair default constructor has been removed. 2021-12-13 09:19:41 +01:00
Michael Nebel
679aad138e C#: Convert System.Collections.Generic.KeyValuePair flow to CSV format. 2021-12-13 09:19:36 +01:00
Michael Nebel
42bf866fb3 C#: Convert System.Web.UI.WebControls.Textbox flow to CSV format. 2021-12-13 09:18:34 +01:00
Michael Nebel
9604ed883c C#: Convert System.NET.IPHostEntry flow to CSV format. 2021-12-13 09:17:27 +01:00
Michael Nebel
d804893a49 C#: Convert System.Net.Cookie flow to CSV format. 2021-12-13 09:16:05 +01:00
Michael Nebel
03fb244545 C#: Convert System.Web.HttpCookie flow to CSV format. 2021-12-13 09:13:14 +01:00
Michael Nebel
a6360215f3 Merge pull request #7304 from michaelnebel/csharp-mad-as-csv2
C#: Convert flow summaries to CSV format.
2021-12-13 08:56:06 +01:00
Harry Maclean
0ca9852cc8 Merge pull request #7325 from github/hmac/action-controller-private-methods
Ruby: Don't count private methods as Rails actions
2021-12-13 20:47:22 +13:00
Harry Maclean
e1d290d4c0 Ruby: Don't count private methods as Rails actions
Private instance methods on ActionController classes aren't valid
request handlers. Routing to them will raise an exception.
2021-12-13 15:36:55 +13:00
Aditya Sharad
1857de1f33 JS: Speed up detection of jQuery marker comments
Combine two regexes into a single one.
This saves up to 5s on large databases by reducing the number
of separate scans of the comments table before regex matching.

The combined regex is slightly more permissive than the
original two, since it allows a combination of the two
matched formats. A string that matches one of the original
regexes will match the combined regex.
2021-12-10 15:30:02 -08:00
Nick Rolfe
b80a84c156 Merge pull request #7341 from github/nickrolfe/cookies 2021-12-10 19:52:23 +00:00
Aditya Sharad
6a1aea740f JS: Avoid scanning individual comment lines to find generated code markers
Some subclasses of GeneratedCodeMarkerComment regex match against `getLine(_)`.
When evaluated, this results in multiple scans (one per subclass that uses it)
of all comment lines in the database, before regex matching against those lines.

To make these scans smaller, regex match against the entire comment text
without splitting them into lines.
This is achieved using `?m` (multiline) and line boundaries in the regexes.
2021-12-10 11:41:54 -08:00
Aditya Sharad
c9a87234ef JS: Factor helper predicate to improve SensitiveWrite performance 2021-12-10 11:41:53 -08: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
Nick Rolfe
b6c5b4d213 Ruby: define ActionViewCookiesCall 2021-12-10 16:36:26 +00: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
Michael Nebel
afa58f5676 C#: Ensure bi-directional importing of external flow for System.Text. 2021-12-10 10:28:35 +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
JrXnm
1a1a7413c2 JS: Improv inter-procedural type inference for FunctionExpr 2021-12-10 01:09:49 +08:00
Michael Nebel
d60b90acd3 C#: Manual update of System.String and System.Convert flow summaries. 2021-12-09 16:34:42 +01:00
Michael Nebel
e879ca7a3b C#: Convert System.Convert flow to CSV format. 2021-12-09 16:34:42 +01:00
Michael Nebel
15b4b218c8 C#: Convert System.Nullable<> flow to CSV format. 2021-12-09 16:34:42 +01:00
Michael Nebel
bbab0e582a C#: Convert System.Lazy<> flow to CSV format. 2021-12-09 16:34:42 +01:00
Michael Nebel
9e61dfb41f C#: Convert System.Text.StringBuilder flow to CSV format. 2021-12-09 16:34:41 +01:00
Michael Nebel
5a26346ba5 C#: Allow the use of pointer types in CSV validation. 2021-12-09 16:34:41 +01:00
Michael Nebel
5376eb89b3 C#: Convert System.String flow to CSV format. 2021-12-09 16:34:41 +01: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
Nick Rolfe
d46564caa6 Ruby: treat ActionController#cookies as a remote flow source 2021-12-09 12:13:17 +00:00
Nick Rolfe
f6a8b9a7e5 Ruby: add cookies call to frameworks test 2021-12-09 12:07:04 +00: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
Henry Mercer
46958e5bff Merge pull request #7168 from erik-krogh/useMinInsteadofRank1
ATM: use min() instead of rank[1]
2021-11-18 14:56:49 +00: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
Anders Schack-Mulligen
6815a13a00 Merge pull request #6931 from hvitved/dataflow/restrict-derived-summaries
Data flow: Restrict derived flow summaries
2021-11-18 15:31:55 +01: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
Erik Krogh Kristensen
2af7817691 use min() instead of rank[1] 2021-11-18 14:26:55 +01:00
Geoffrey White
6c2713dd8b Merge pull request #7159 from MathiasVP/pointers-are-always-iterators
C++: Always recognize pointers as iterators
2021-11-18 11:14:44 +00:00
Tony Torralba
9d22ec88fd Merge pull request #7165 from github/workflow/coverage/update
Update CSV framework coverage reports
2021-11-18 10:37:34 +01:00
Erik Krogh Kristensen
1cca377e7d Merge pull request #6561 from erik-krogh/htmlReg
JS/Py/Ruby: add a bad-tag-filter query
2021-11-18 09:39:13 +01:00
github-actions[bot]
ecdaeb0c10 Add changed framework coverage reports 2021-11-18 00:09:24 +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
Mathias Vorreiter Pedersen
c998370c84 C++: Accept more test changes. 2021-11-17 15:22:17 +00:00
Mathias Vorreiter Pedersen
36585a7469 C++: Accept test changes. 2021-11-17 14:41:30 +00:00
Mathias Vorreiter Pedersen
6dc6a78293 C++: Add a 'IteratorByPointer' class so pointers are always iterators. 2021-11-17 14:41:19 +00:00
Alex Ford
08b6a17097 Merge pull request #7151 from github/ruby/methodcallnode
Ruby: add `getMethodName` predicate to `DataFlow::CallNode` class
2021-11-17 14:40:07 +00:00
Anders Schack-Mulligen
22ebe68b1b Merge pull request #7132 from aschackmull/java/overrides
Java: Fix overrides to not be transitive.
2021-11-17 15:38:11 +01:00
Anders Schack-Mulligen
1645fcf79c Merge pull request #7088 from aschackmull/java/parameterized-subtyping
Java: Improve algorithm for subtyping of parameterized types.
2021-11-17 15:28:28 +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
Arthur Baars
5ddfb37f29 Merge pull request #7155 from aibaars/ruby-qualified-import
Ruby: QL generator: use qualified imports
2021-11-17 12:40:14 +01:00
Arthur Baars
6f24947ec6 Merge pull request #7156 from aibaars/ruby-prepare-db-upgrade-fix
Ruby: Fix scripts/prepare-db-upgrade.sh
2021-11-17 12:39:55 +01:00
Benjamin Muskalla
3c3a65243f Merge pull request #6664 from bmuskalla/bmuskalla/modelGenerator
Java: Initial CSV model generator
2021-11-17 12:30:45 +01:00
Arthur Baars
fbb3e8d780 Fix scripts/prepare-db-upgrade.sh 2021-11-17 12:11:20 +01:00
Geoffrey White
d232283647 Merge pull request #7149 from geoffw0/non-https-url2
C++: Minor improvements to 'Failure to use HTTPS URLs' query
2021-11-17 10:05:30 +00:00
Tom Hvitved
4eacbd1cbe Ruby: Sync files 2021-11-17 10:49:51 +01:00
Tom Hvitved
6d58dd2823 Java: Update expected test output 2021-11-17 10:49:51 +01:00
Tom Hvitved
3da73b9001 C#: Update expected test output 2021-11-17 10:49:49 +01:00
Tom Hvitved
58dd75881c C#: Update flow summary to avoid negative recursion 2021-11-17 10:39:13 +01:00
Tom Hvitved
ac41451798 Data flow: Sync files 2021-11-17 10:39:12 +01:00
Tom Hvitved
0c1285f5d9 Data flow: Restrict derived flow summaries 2021-11-17 10:39:12 +01:00
Arthur Baars
7c2841f058 Ruby: QL generator: use qualified imports 2021-11-17 10:37:44 +01:00
Erik Krogh Kristensen
474c808373 Merge pull request #7137 from erik-krogh/functionExport
JS: recognize library inputs when the library exports "through" a function
2021-11-17 09:49:02 +01:00
Tom Hvitved
08c778241d Ruby: Adopt to changes after rebase 2021-11-17 09:17:32 +01:00
Anders Schack-Mulligen
69671ce90d Java: cache overrides 2021-11-17 09:16:58 +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
Tom Hvitved
7cfc696d62 Merge pull request #7141 from hvitved/ruby/synthesis-realnode-recursion
Ruby: Eliminate unnecessary recursion through `RealNode`
2021-11-17 09:03:30 +01:00
Pierre
f846915b58 Merge pull request #7069 from github/turbo-apple-silicon-requirements-1
Add requirements for Apple Silicon
2021-11-17 00:04:06 +01:00
Alex Ford
c8cdbfa352 ruby: push getMethodName into DataFlow::CallNode 2021-11-16 17:11:26 +00:00
Benjamin Muskalla
b4eadefb92 Fix test 2021-11-16 17:28:01 +01:00
Alex Ford
286c894f34 ruby: add DataFlow::MethodCallNode class 2021-11-16 15:39:47 +00:00
Chris Smowton
188915e597 Fix typos 2021-11-16 15:30:00 +00:00
Anders Schack-Mulligen
76606b5995 Java: Add more comments. 2021-11-16 16:11:14 +01:00
Geoffrey White
ea9640a39d C++: Autoformat. 2021-11-16 14:26:42 +00:00
Anders Schack-Mulligen
d408105fad Java: Fix bad join-order. 2021-11-16 14:25:19 +01:00
Geoffrey White
5ef71e6ef3 C++: Add a few more sinks. 2021-11-16 13:02:56 +00:00
Tom Hvitved
9e8e2e2b48 Ruby: Update CFG test output (some nodes have been reordered) 2021-11-16 12:45:24 +01:00
Tom Hvitved
e7b091086d Ruby: Eliminate unnecessary recursion through RealNode 2021-11-16 12:24:17 +01:00
Geoffrey White
aafa5762ad C++: Add a CWE tag associated with OWASP A8. 2021-11-16 11:21:25 +00: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
Benjamin Muskalla
0e6bb28016 Only consider store steps 2021-11-16 10:46:24 +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
Erik Krogh Kristensen
b9ea4a8709 recognize library inputs when the library exports "through" a function 2021-11-15 22:43:38 +01:00
Benjamin Muskalla
fd9199c0c0 Simplify handling of tainting fields 2021-11-15 16:40:09 +01:00
Benjamin Muskalla
d7ed325b3f Refactor content flow into predicate 2021-11-15 16:30:55 +01:00
Benjamin Muskalla
f4310898b3 Capture sources flowing into parameters 2021-11-15 16:28:28 +01:00
Anders Schack-Mulligen
1cd42ea668 Java: Fix test and some references. 2021-11-15 16:03:04 +01:00
Benjamin Muskalla
8040d9cfcf Only consider true return statements as sinks 2021-11-15 15:29:01 +01:00
Benjamin Muskalla
e6e52a3b32 190 2021-11-15 15:18:03 +01:00
Anders Schack-Mulligen
c616f5784d Java: Fix overrides to not be transitive. 2021-11-15 13:54:53 +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
Benjamin Muskalla
dc022430ee Remove superflous instanceof 2021-11-15 13:07:02 +01:00
Benjamin Muskalla
412bd32f45 Move more predicates into configuration 2021-11-15 13:04:23 +01:00
Benjamin Muskalla
b84c03672d Prefer types to TargetAPI 2021-11-15 12:43:46 +01:00
Benjamin Muskalla
bca6cecd1c Remove basic support for lambda flow 2021-11-15 12:38:30 +01:00
Benjamin Muskalla
78e3906ea7 Exclude more JDK internals 2021-11-15 11:58:10 +01:00
Benjamin Muskalla
cce3780481 Restrict param2return value features 2021-11-15 09:57:23 +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
Benjamin Muskalla
a0b7f267ff Only capture taint from own fields
Also exclude `Charset` as relevant taint-carrying type. This is generally
what we want to lets us avoid tracking arguments that lead to FP.
2021-11-12 10:15:15 +01:00
Benjamin Muskalla
0234e77d2f Let sink node be pluggable in any call context 2021-11-12 09:43:05 +01:00
Benjamin Muskalla
b8809a20d8 Support propagating taint of inner object 2021-11-12 09:39:59 +01:00
Erik Krogh Kristensen
b639a8d183 update ruby example
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2021-11-11 14:04:38 +01: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
Benjamin Muskalla
2d4176bec0 Ignore Number-derived types 2021-11-10 16:30:27 +01:00
Benjamin Muskalla
dbd393b77a Support flow into field of referenced objects 2021-11-10 16:30:27 +01:00
Benjamin Muskalla
974c7b0898 Avoid cross-class flow for field writes 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
74ac234f1c Restrict field access to same type 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
8740e879b4 Fix docs 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
a546b38ee0 Restrict field access to corresponding type 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
6960a7b97e Remove extraneous last column 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
ef972159a6 Fix bug when generating output in a subfolder 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
4cfd978bfe Support generating in respective folders 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
b92758883b Auto-format generated qll files 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
e2bd792fc2 Consider bulk-like data for argument accessors 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
739fe75194 Support flow for factory and strategy pattern
* Support models for factories that create
new instances of an object while tainting it with incoming data
* Support models to infer super types for
private implementations to expose the models
at the right level
2021-11-10 16:30:24 +01:00
Benjamin Muskalla
58de6d143f Add docs to explain the models captured by the predicates 2021-11-10 16:30:24 +01:00
Benjamin Muskalla
747ab122c3 Restrict fluent api models to same type access 2021-11-10 16:30:24 +01:00
Benjamin Muskalla
8564c9001a Fix naming for source nodes 2021-11-10 16:30:24 +01:00
Benjamin Muskalla
9500c9c8bc Support lambda flow for source models
Also rely on public API to detect the source node
2021-11-10 16:30:24 +01:00
Benjamin Muskalla
35baa1c3df Support bulkdata for boxed types as well 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
83b4070f31 Fix bug to accept bulk data for char/byte arrays 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
281f25403d Match enclosing unit without casting to specific nodes 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
bc10fd94cb Support generating only specific models 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
0e9fcc6c39 Only generate models for local supertypes
Avoid generating models for classes
implementing external SPI (e.g. `FileFilter`).
Keep `toString` models intact as they're
commonly used as taint-propagation method
(e.g. see `Joiner`).
2021-11-10 16:30:23 +01:00
Benjamin Muskalla
157f56f48a Capture model for defining interface
Instead of modeling individual implementations, take a more general
approach of reuse dataflows for interfaces defined by a library. This allows
tracking flows across all implementations and aligns better with how we
manually model frameworks. This may have some FPs given all possible flows
are modeled for a specific interface but also covers more scenarios where
we don't know which implementation of an interface is used.
2021-11-10 16:30:22 +01:00
Benjamin Muskalla
f36bb8baaf Exclude models for simpler types
Avoid generating models for types that can't really propagate taint
in a valuable way (e.g. primitivies, BigInt, ..). Keep tracking
bulk-like data (e.g. char[] or byte[]).
2021-11-10 16:30:22 +01:00
Benjamin Muskalla
842f617bc1 Order sinks and sources first 2021-11-10 16:30:22 +01:00
Benjamin Muskalla
be150f269b Formatting 2021-11-10 16:30:22 +01:00
Benjamin Muskalla
2654e27123 Exclude known internal APIs from being modeled 2021-11-10 16:30:22 +01:00
Benjamin Muskalla
6b2460d4a1 Formatting 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
060862ab3b Avoid certain test sources in models 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
e607953b9c Simplify query 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
9a859334d4 Formatting 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
6c59333716 Remove workaround that accounted for missing flow 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
7dae6122d9 Support CharSequence#toString
Given CharSequence is often used as an
alias for String, ensure taint through toString is flowing
2021-11-10 16:30:20 +01:00
Benjamin Muskalla
ca9d5439f0 Restrict source configuration to return nodes 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
7a7ec06819 Simplify sink configuration 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
1a4fd7bc7d Allow camelcase names 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
2b2ac82fb7 Fix bug in sink detection 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
c616eb1473 Fix finding more sources 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
38579ef25b Add proper metadata to queries 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
a80d50cbc0 Simplify field flow 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
a1d8dfb524 Initial support for source models 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
c844f5382f Add script to generate flow models 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
f9fea15a52 Initial support for capturing sink models 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
364de55b8d Support parameter->parameter flow 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
cd11ef3bf6 Support outgoing taint flow from fields 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
c3462be2c9 Capture argument->return value flows 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
4ca006ba3d Only expose visible innner classes 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
88032afdc3 Add test for final class 2021-11-10 16:30:17 +01:00
Benjamin Muskalla
ec772fb6b2 Add support for qualifier flow 2021-11-10 16:30:17 +01:00
Benjamin Muskalla
32ef40c77b Add scaffolding for summary model generator 2021-11-10 16:30:17 +01: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
Anders Schack-Mulligen
1efe1e0d10 Java: Improve algorithm for subtyping of parameterized types. 2021-11-09 15:49:17 +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
Pierre
4af3775b72 Add requirements for Apple Silicon 2021-11-08 01:37:31 +01: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
Erik Krogh Kristensen
02f500b9c2 Merge branch 'main' into htmlReg 2021-11-04 12:58:42 +01: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
Erik Krogh Kristensen
8a4b043cb1 fix imports 2021-10-26 15:39:45 +02:00
Erik Krogh Kristensen
62e729501c make the RegExpEscape::getUnescaped predicate public in python 2021-10-26 15:25:14 +02:00
Erik Krogh Kristensen
97264b5dda add the bad tag filter query to ruby 2021-10-26 15:25:12 +02:00
Erik Krogh Kristensen
c15ddf6e92 update ReDoSUtil in ruby 2021-10-26 15:03:09 +02:00
Erik Krogh Kristensen
2ddf445caf move ruby files to match file structure from js/py 2021-10-26 14:54:12 +02:00
Erik Krogh Kristensen
44afa34e37 Merge branch 'main' of github.com:github/codeql into htmlReg 2021-10-26 14:46:27 +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
Erik Krogh Kristensen
8d6cac76cc apply suggestions from asgerf 2021-10-04 12:45:02 +02:00
Erik Krogh Kristensen
aafae24ef2 update qhelp 2021-09-28 23:11:02 +02:00
Erik Krogh Kristensen
8d556ed1e1 Update python/ql/lib/semmle/python/security/BadTagFilterQuery.qll
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
2021-09-28 23:04:28 +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
Erik Krogh Kristensen
99ed4a1a89 add a bad-tag-filter query for Python and JavaScript 2021-09-21 15:04:03 +02:00
Erik Krogh Kristensen
fd64ff9ef1 don't give group numbers to non-capturing groups 2021-09-21 12:15:27 +02:00
Erik Krogh Kristensen
c40ffab093 make isStartState public in ReDoSUtil 2021-09-21 12:14:21 +02:00
Erik Krogh Kristensen
672e4a3d72 cache TopLevel::isMinified 2021-09-21 12:13:37 +02:00
Erik Krogh Kristensen
60993214d5 cache isInterpretedAsRegExp 2021-09-21 12:13:37 +02:00
Erik Krogh Kristensen
01e345c2cc implement RegExpWordBoundary in RegexTreeView 2021-09-21 12:13:37 +02:00
Erik Krogh Kristensen
8535e6f281 use toUnicode in RegexTreeView 2021-09-21 12:13:37 +02:00
luchua-bc
8170f01b66 Query to detect uncontrolled thread resource consumption 2021-09-20 02:12:47 +00:00
1518 changed files with 71785 additions and 28322 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

@@ -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",
@@ -471,7 +472,12 @@
"ReDoS Polynomial Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/regexp/SuperlinearBackTracking.qll"
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll"
],
"BadTagFilterQuery Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
"ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll"
],
"CFG": [
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",

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

@@ -1,4 +1,7 @@
lgtm,codescanning
## 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

@@ -34,6 +34,16 @@ private class IteratorByTraits extends Iterator {
IteratorByTraits() { exists(IteratorTraits it | it.getIteratorType() = this) }
}
/**
* The C++ standard includes an `std::iterator_traits` specialization for pointer types. When
* this specialization is included in the database, a pointer type `T*` will be an instance
* of the `IteratorByTraits` class. However, if the `T*` specialization is not in the database,
* we need to explicitly include them with this class.
*/
private class IteratorByPointer extends Iterator instanceof PointerType {
IteratorByPointer() { not this instanceof IteratorByTraits }
}
/**
* A type which has the typedefs expected for an iterator.
*/

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

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

@@ -0,0 +1,12 @@
## 0.0.5
### New Queries
* A new query `cpp/certificate-not-checked` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.
* A new query `cpp/certificate-result-conflation` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.
## 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
)
}

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