Compare commits

..

204 Commits

Author SHA1 Message Date
Jean Helie
c080ee92fd ML: update expected tests outputs 2022-04-08 13:46:37 +02:00
Jean Helie
7a95c4a465 ML: add defensive check to ensure Unknown endpoints cannot also be NotASink 2022-04-08 13:46:37 +02:00
Asger F
e5f2b830f3 Merge pull request #8577 from asgerf/fix-mad-warning
JS/Ruby: Fix regexp in MaD checking
2022-03-28 15:29:16 +02:00
Asger F
f22df765ed Merge pull request #8533 from asgerf/mad-receiver-token
JS/Ruby: Represent non-positional arguments with Argument/Parameter tokens
2022-03-28 15:28:52 +02:00
Asger Feldthaus
0b30ecf36a Ruby: add select clause back to Summaries.ql 2022-03-28 13:57:50 +02:00
Asger Feldthaus
d5bcd14733 Sync ApiGraphModels.qll 2022-03-28 12:43:55 +02:00
Asger Feldthaus
7e6206ed36 JS: Fix the regexp for valid MaD token arguments 2022-03-28 12:43:43 +02:00
Arthur Baars
af1d949d06 Merge pull request #8489 from aibaars/regex-refactor
Ruby: refactor regex libraries
2022-03-28 12:17:00 +02:00
Erik Krogh Kristensen
c98d024c0e Merge pull request #8575 from erik-krogh/qlFixTypo
QL: fix Import::getImportString
2022-03-28 11:41:59 +02:00
Arthur Baars
accdd9499a Ruby: drop unused predicates that do not exist in Python variant 2022-03-28 11:32:52 +02:00
Erik Krogh Kristensen
7ac6f5849c fix Import::getImportString 2022-03-28 11:04:18 +02:00
Mathias Vorreiter Pedersen
57c39e9642 Merge pull request #8574 from erik-krogh/qlForQlFixes
QL: two small improvements
2022-03-28 09:26:43 +01:00
Erik Krogh Kristensen
77aff04429 add a getImportString utility predicate to Import 2022-03-28 10:14:27 +02:00
Erik Krogh Kristensen
d4c8f42336 add QLDoc to the child relation for TopLevel 2022-03-28 09:54:08 +02:00
yoff
5efc19c39d Merge pull request #7806 from erik-krogh/pyDef
Python: Add def nodes to API graphs
2022-03-28 08:09:14 +02:00
Edoardo Pirovano
8faabb837a Merge pull request #8561 from erik-krogh/latestTools
QL: use latest tools in codeql-action/init
2022-03-25 15:12:58 -04:00
Erik Krogh Kristensen
21192b7593 use latest tools in codeql-action/init 2022-03-25 19:26:10 +01:00
Andrew Eisenberg
5fb84a774b Merge pull request #8553 from github/aeisenberg/cpp-suites
Suites: Remove self-referential `from` directives
2022-03-25 09:15:53 -07:00
Michael Nebel
79f3da8af1 Merge pull request #8506 from michaelnebel/java/generalize-generate-flow-model
Java/C#: Generalize script for generating flow models.
2022-03-25 16:20:53 +01:00
Geoffrey White
2014599f88 Merge pull request #8318 from geoffw0/cwe497b
C++: New query cpp/potential-system-data-exposure
2022-03-25 14:55:00 +00:00
Taus
b75ac4e827 Merge pull request #8540 from tausbn/python-add-points-to-call-graph-meta-query
Python: Add call graph meta-query
2022-03-25 15:36:33 +01:00
Erik Krogh Kristensen
9e71d9bada Merge pull request #8556 from erik-krogh/bumpAction
QL: update codeql-action version in QL-for-QL
2022-03-25 14:46:31 +01:00
Erik Krogh Kristensen
68c07fe1c0 pin the commit of codeql-action in the remaining steps/workflows 2022-03-25 14:35:44 +01:00
Erik Krogh Kristensen
8f377f4101 pin the commit
Co-authored-by: Esben Sparre Andreasen <esbena@github.com>
2022-03-25 14:19:29 +01:00
Erik Krogh Kristensen
cf57eb825c update codeql-action version in QL-for-QL 2022-03-25 13:37:27 +01:00
Taus
d56caa2398 Merge pull request #8547 from RasmusWL/regexstring-imports
Python: Import framework-modeling in `regex.qll`
2022-03-25 13:26:04 +01:00
Geoffrey White
9f3fd57534 Merge branch 'main' into cwe497b 2022-03-25 11:57:30 +00:00
Mathias Vorreiter Pedersen
c115c68247 Merge pull request #8542 from MathiasVP/public-iterated-dominance-frontier
C++: Use `iterated (post)dominance frontier` algorithm in `IRBlock`
2022-03-25 11:51:15 +00:00
Jeroen Ketema
b91914bd89 Merge pull request #8534 from jketema/bitwise-ctor-field-init
C++: Handle bitwise copies in copy constructors
2022-03-25 12:47:57 +01:00
Geoffrey White
e377eebdbc C++: More 'adversary' -> 'malicious user' and related doc changes. 2022-03-25 11:34:37 +00:00
Geoffrey White
11074b6d77 Update cpp/ql/src/Security/CWE/CWE-497/PotentiallyExposedSystemData.ql
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2022-03-25 11:08:07 +00:00
Geoffrey White
6b6ee61d3f Apply suggestions from code review
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2022-03-25 11:06:46 +00:00
Jeroen Ketema
94f014d948 C++: Update tests for handling of bitwise copies in copy constructors 2022-03-25 11:43:01 +01:00
Jeroen Ketema
b18b86b2e2 C++: Remove check for value-less literals in constructors 2022-03-25 11:43:01 +01:00
Chris Smowton
f0168d00d1 Merge pull request #8529 from github/smowton/admin/commons-lang3-test-typo
Java: Fix harmless search-replace mistake
2022-03-25 10:36:00 +00:00
Asger Feldthaus
8e2ffc2508 Ruby: add the inline test expectations 2022-03-25 11:31:22 +01:00
Asger Feldthaus
5703f63afa Ruby: use InlineFlowTest in Summaries.ql test 2022-03-25 11:18:52 +01:00
Erik Krogh Kristensen
cf94c93b1a Merge pull request #8481 from erik-krogh/schemeChain
JS: recognize string replacement chains as scheme checks in js/incomplete-url-scheme-check
2022-03-25 11:13:10 +01:00
Andrew Eisenberg
99f14af56a Suites: Remove self-referential from directives
Fixes https://github.com/github/codeql/issues/8412

See https://github.com/github/codeql/issues/8412#issuecomment-1078281668
for more detail.
2022-03-24 14:19:20 -07:00
Tom Hvitved
e12b6df118 Merge pull request #8484 from hvitved/ruby/constant-value-rework
Ruby: Rework `getConstantValue` implementation
2022-03-24 14:32:31 +01:00
Rasmus Wriedt Larsen
d51aaf2f91 Python: Import framework-modeling in regex.qll 2022-03-24 14:28:44 +01:00
Mathias Vorreiter Pedersen
80630972b1 Merge branch 'main' into public-iterated-dominance-frontier 2022-03-24 12:50:29 +00:00
Rasmus Wriedt Larsen
98c0d73ffe Merge pull request #8524 from RasmusWL/ruby-update-ssrf-concept
Ruby: Minor change of SSRF concept
2022-03-24 13:48:06 +01:00
Chris Smowton
005a020f04 Merge pull request #8508 from igfoo/igfoo/error_elements
Java: Add ErrorExpr, ErrorStmt
2022-03-24 10:39:14 +00:00
Arthur Baars
15801fcc85 Apply suggestions from code review
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2022-03-24 11:37:03 +01:00
Arthur Baars
eef0da09bb Ruby: move RegExpTreeView.qll out of 'internal' 2022-03-24 11:37:03 +01:00
Arthur Baars
1a9aaf4543 Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2022-03-24 11:37:03 +01:00
Arthur Baars
5f787144c0 Add change note 2022-03-24 11:37:03 +01:00
Arthur Baars
3c434931ec Ruby: make ParseRegExp.qll and RegExpTreeView.qll internal libraries 2022-03-24 11:37:03 +01:00
Arthur Baars
74aea81fe3 Ruby: refactor regex libraries 2022-03-24 11:37:02 +01:00
Arthur Baars
496aab78a7 Merge pull request #8535 from aibaars/setter-method-arg-location
Ruby: fix location of setter-call argument
2022-03-24 11:26:13 +01:00
Tom Hvitved
eff7cf6396 Merge pull request #8538 from hvitved/ruby/regexpterm-location-perf
Ruby: Fix bad join-order in `RegExpTerm::hasLocationInfo`
2022-03-24 10:01:12 +01:00
Tom Hvitved
2699412160 Merge pull request #8543 from hmac/hmac/test-naming-fix
Ruby: Fix bad name of lambda in test
2022-03-24 09:46:04 +01:00
Harry Maclean
28a430a2f2 Ruby: Fix bad name of lambda in test
This isn't the identity function, so it's confusing for it to be named
so.
2022-03-24 12:44:41 +13:00
Harry Maclean
3b4206cebf Merge pull request #8517 from hmac/hmac/lambda-captured-var
Ruby: fix bug with captured variable reads in lambdas
2022-03-24 10:00:19 +13:00
Mathias Vorreiter Pedersen
61c944201f Merge pull request #8461 from Paul1nh0/dev_cve_2016_6480
Add query for double-fetch vulnerability
2022-03-23 18:15:05 +00:00
Asger Feldthaus
b0b795dbbb JS: Autoformat 2022-03-23 19:15:01 +01:00
Mathias Vorreiter Pedersen
c76a323246 C++/C#: Sync identical files. 2022-03-23 17:27:25 +00:00
Mathias Vorreiter Pedersen
1b4fb45089 C++: Use the iterated (post)dominance frontier algorithm in the public '(post)dominanceFrontier' predicate on 'IRBlocks'. 2022-03-23 17:27:16 +00:00
Asger Feldthaus
69eb24e748 Ruby: fix toCsv representation of argument/parameter positions 2022-03-23 18:11:09 +01:00
Asger Feldthaus
6870a19ace Ruby: autoformat 2022-03-23 18:06:12 +01:00
Asger Feldthaus
0d51804b5e Ruby: update a comment mentioning Receiver 2022-03-23 18:06:12 +01:00
Asger Feldthaus
ce54eb3c78 Ruby: Add Argument[foo:] syntax for keyword arguments 2022-03-23 18:06:12 +01:00
Asger Feldthaus
c923b9bb9b Ruby: Replace Receiver with Argument[self] 2022-03-23 18:06:12 +01:00
Asger Feldthaus
ec30a0f975 Ruby: replace BlockArgument with Argument[block] 2022-03-23 18:06:12 +01:00
Asger Feldthaus
6d84baf276 Ruby: Support self,block in Argument/Parameter tokens 2022-03-23 18:06:12 +01:00
Asger Feldthaus
95122b2b6c JS: Support Argument[this] token 2022-03-23 18:06:12 +01:00
Asger Feldthaus
d476f976fe JS: Support Parameter[this] token 2022-03-23 18:06:12 +01:00
Taus
af888f7604 Python: Add call graph meta-query 2022-03-23 16:36:28 +00:00
CodeQL CI
ac29d5f51b Merge pull request #8523 from asgerf/js/api-graph-receiver-label
Approved by erik-krogh
2022-03-23 15:31:12 +00:00
Mathias Vorreiter Pedersen
8b8f0ca6e5 Merge pull request #8479 from geoffw0/widecharperf
C++: Fix expensive getWideCharType().
2022-03-23 14:22:17 +00:00
Anna Railton
41418e729e Merge pull request #8536 from github/codeql-ci/js-atm-new-release
JS: Bump version numbers of ML-powered packs after 0.2.0 release
2022-03-23 14:16:11 +00:00
Tom Hvitved
13be99196f Ruby: Fix bad join-order in RegExpTerm::hasLocationInfo
Before:
```
[2022-03-23 14:50:16] (776s) Tuple counts for RegExpTreeView::RegExpTerm::hasLocationInfo#dispred#f0820431#ffffff/6@5f6cf7if after 1m4s:
                      707103    ~7%     {2} r1 = SCAN Literal::StringlikeLiteral::getNumberOfComponents#dispred#f0820431#ff OUTPUT In.0, (In.1 - 1)
                      64721     ~0%     {5} r2 = JOIN r1 WITH RegExpTreeView::RegExpTerm#7783c185#ffff_1023#join_rhs ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Rhs.1 'this', Rhs.2, Rhs.3
                      64721     ~0%     {5} r3 = JOIN r2 WITH Literal::StringlikeLiteral::getComponent#dispred#f0820431#fff ON FIRST 2 OUTPUT Rhs.2, Lhs.0, Lhs.2 'this', Lhs.3, Lhs.4
                      64721     ~0%     {5} r4 = JOIN r3 WITH AST::AstNode::getLocation#dispred#f0820431#bf ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2 'this', Lhs.3, Lhs.4
                      64721     ~3%     {6} r5 = JOIN r4 WITH Locations::Location::hasLocationInfo#dispred#f0820431#ffffff ON FIRST 1 OUTPUT Rhs.1 'filepath', Lhs.1, Lhs.2 'this', Lhs.3, Lhs.4, Rhs.4 'endline'
                      353247577 ~1%     {10} r6 = JOIN r5 WITH Locations::Location::hasLocationInfo#dispred#f0820431#ffffff_1023#join_rhs ON FIRST 1 OUTPUT Lhs.1, 0, Lhs.2 'this', Lhs.3, Lhs.4, Lhs.0 'filepath', Lhs.5 'endline', Rhs.1, Rhs.2 'startline', Rhs.3
                      353247577 ~0%     {9} r7 = JOIN r6 WITH Literal::StringlikeLiteral::getComponent#dispred#f0820431#fff ON FIRST 2 OUTPUT Rhs.2, Lhs.7, Lhs.2 'this', Lhs.3, Lhs.4, Lhs.5 'filepath', Lhs.6 'endline', Lhs.8 'startline', Lhs.9
                      64721     ~2%     {6} r8 = JOIN r7 WITH AST::AstNode::getLocation#dispred#f0820431#bf ON FIRST 2 OUTPUT Lhs.2 'this', Lhs.5 'filepath', Lhs.7 'startline', (Lhs.8 + Lhs.3), Lhs.6 'endline', ((Lhs.8 + Lhs.4) - 1)
                                        return r8
```

After:
```
[2022-03-23 14:58:35] (247s) Tuple counts for RegExpTreeView::RegExpTerm::componentHasLocationInfo#f0820431#fbfffff/7@de55ac7l after 1.1s:
                      12956   ~0%     {3} r1 = SCAN files OUTPUT In.0, 0, In.1 'filepath'
                      9850785 ~0%     {7} r2 = JOIN r1 WITH locations_default_102345#join_rhs ON FIRST 1 OUTPUT Rhs.1, 0, Lhs.2 'filepath', Rhs.2 'startline', Rhs.3 'startcolumn', Rhs.4 'endline', Rhs.5 'endcolumn'
                      823486  ~0%     {8} r3 = JOIN r2 WITH AST::AstNode::getLocation#dispred#f0820431#bf_10#join_rhs ON FIRST 1 OUTPUT 0, Rhs.1, 0, Lhs.2 'filepath', Lhs.3 'startline', Lhs.4 'startcolumn', Lhs.5 'endline', Lhs.6 'endcolumn'
                      698251  ~4%     {7} r4 = JOIN r3 WITH Literal::StringlikeLiteral::getComponent#dispred#f0820431#fff_120#join_rhs ON FIRST 2 OUTPUT Rhs.2, 0, Lhs.3 'filepath', Lhs.4 'startline', Lhs.5 'startcolumn', Lhs.6 'endline', Lhs.7 'endcolumn'
                      64721   ~1%     {7} r5 = JOIN r4 WITH RegExpTreeView::RegExpTerm#7783c185#ffff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', 0, Lhs.2 'filepath', Lhs.3 'startline', Lhs.4 'startcolumn', Lhs.5 'endline', Lhs.6 'endcolumn'
                                      return r5

[2022-03-23 14:58:35] (247s) Tuple counts for RegExpTreeView::RegExpTerm::hasLocationInfo#dispred#f0820431#ffffff/6@ad66b12q after 53ms:
                      707103 ~7%     {2} r1 = SCAN Literal::StringlikeLiteral::getNumberOfComponents#dispred#f0820431#ff OUTPUT In.0, (In.1 - 1)
                      64721  ~0%     {4} r2 = JOIN r1 WITH RegExpTreeView::RegExpTerm#7783c185#ffff_1023#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', Lhs.1, Rhs.2, Rhs.3
                      64721  ~5%     {5} r3 = JOIN r2 WITH project#RegExpTreeView::RegExpTerm::componentHasLocationInfo#f0820431#bffffff ON FIRST 2 OUTPUT Lhs.0 'this', Rhs.2 'filepath', Lhs.2, Lhs.3, Rhs.3 'endline'
                      64721  ~2%     {6} r4 = JOIN r3 WITH project#RegExpTreeView::RegExpTerm::componentHasLocationInfo#f0820431#fbfffff ON FIRST 2 OUTPUT Lhs.0 'this', Lhs.1 'filepath', Rhs.2 'startline', (Rhs.3 + Lhs.2), Lhs.4 'endline', ((Rhs.3 + Lhs.3) - 1)
                                     return r4
```
2022-03-23 14:55:06 +01:00
Geoffrey White
9ae1ec69dc C++: Autoformat. 2022-03-23 13:37:39 +00:00
Michael Nebel
6804e20e4a Merge pull request #8451 from michaelnebel/csharp/modelgenerator-improvements
C#: Model generator improvements and more tests
2022-03-23 13:30:58 +01:00
Arthur Baars
06a99c3987 Ruby: fix location of setter-call argument 2022-03-23 12:55:52 +01:00
github-actions[bot]
1e620c99c6 JS: Bump patch version of ML-powered library and query packs post-release 2022-03-23 11:53:34 +00:00
github-actions[bot]
dc0c8374d2 JS: Bump minor version of ML-powered library and query packs 2022-03-23 11:47:53 +00:00
github-actions[bot]
2b42d84ccd JS: Bump patch version of ML-powered model pack post-release 2022-03-23 11:47:53 +00:00
github-actions[bot]
6fbc0e6e32 JS: Bump ML model pack dependency of ML-powered model building and query packs 2022-03-23 11:47:53 +00:00
github-actions[bot]
8d13662315 JS: Bump minor version of ML-powered model pack 2022-03-23 11:47:08 +00:00
yoff
647d37492d Merge pull request #8289 from tausbn/python-remove-with-test-syntax-error
Python: Fix syntax error in `with` test output
2022-03-23 12:25:11 +01:00
Mathias Vorreiter Pedersen
a81024a485 Merge pull request #8525 from MathiasVP/more-precise-is-before
C++: Consider columns in `Location.isBefore`
2022-03-23 11:04:34 +00:00
Mathias Vorreiter Pedersen
0eab54d385 Merge pull request #8491 from jketema/command-line-injection-with-flow-state
C++: Use flow states in `cpp/command-line-injection`
2022-03-23 11:03:29 +00:00
Michael Nebel
b204f783fb C#: Remove special handling of bulk types. 2022-03-23 11:26:49 +01:00
Rasmus Wriedt Larsen
671889372b Ruby: Update wording of change-note
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2022-03-23 11:26:41 +01:00
Rasmus Wriedt Larsen
e66932c728 Ruby: Make deprecated getURL work with new modeling
So an "old" query using the deprecated predicate, will still find the
same results, even when the modeling has been updated.
2022-03-23 11:22:34 +01:00
Tom Hvitved
4bcd4d75a9 Address review comments 2022-03-23 11:22:25 +01:00
Asger Feldthaus
f2285709bd JS: Change note 2022-03-23 10:42:51 +01:00
Asger Feldthaus
59d5c54432 JS: Update test output from knex 2022-03-23 10:42:51 +01:00
Asger Feldthaus
73071bdc08 JS: Change getAParameter to not return the receiver 2022-03-23 10:42:51 +01:00
Asger Feldthaus
6bef5a70b3 JS: Add dedicated API graph label for receiver, instead of parameter -1 2022-03-23 10:42:51 +01:00
Mathias Vorreiter Pedersen
a84ee50af0 Update cpp/ql/src/change-notes/2022-03-21-command-line-injection-with-flow-states.md 2022-03-23 09:35:41 +00:00
Michael Nebel
bbe28bc668 Java: Do not explicitly require python3 when executing the GenerateFlowModel.py. 2022-03-23 10:35:32 +01:00
Michael Nebel
7eddc1e7ec Java: Adjust scripts for new location. 2022-03-23 10:35:32 +01:00
Michael Nebel
7fc11be787 Java: Move generate_flow_model file into a shared models-as-data script folder. 2022-03-23 10:35:32 +01:00
Michael Nebel
bd89de3c43 Java: Make sure to use python3 during workflow execution (required for python string interpolation). 2022-03-23 10:35:32 +01:00
Michael Nebel
6c9d1a3edb Java: Make standalone library for shared functionality. 2022-03-23 10:35:32 +01:00
Michael Nebel
9564f8bf5c Java: Put remainings parts of the generator code into the class. 2022-03-23 10:35:32 +01:00
Michael Nebel
20414c0e56 Java: Move Generator creation into class definition. 2022-03-23 10:35:32 +01:00
Michael Nebel
3f33cdf688 Java: Introduce generator class. 2022-03-23 10:35:32 +01:00
Michael Nebel
6ed1424679 Java: Refactor language specific parts into variable. 2022-03-23 10:35:32 +01:00
Michael Nebel
1ac988323a Java: Add dry-run optional paramteter to generator script. 2022-03-23 10:35:31 +01:00
Michael Nebel
586fd5a43b Java: Rename file for generating flow models. 2022-03-23 10:35:31 +01:00
Rasmus Wriedt Larsen
bbf60b875e Merge pull request #8476 from RasmusWL/shared-concepts-scaffolding
Python/JS/Ruby: Shared concepts scaffolding
2022-03-23 10:22:42 +01:00
Paul1nh0
5a1dc61d9d modify arguments check logic
As far as I can tell, root cause of double-fetech issue is read from the same user mode memory twice, so it makes sense that only check whether user mode pointer is same or not
2022-03-23 11:20:08 +08:00
Paul1nh0
6a6cd61d83 automated using CodeQL for VSCode extension 2022-03-23 09:37:45 +08:00
Mathias Vorreiter Pedersen
01929d484e Merge pull request #8526 from MathiasVP/internal-diagmetric-queries-ql
C++: Add internal `ExtractionError` query
2022-03-22 17:26:38 +00:00
Owen Mansel-Chan
efc0d95535 Merge pull request #8528 from github/smowton/admin/fix-go-doc-links
Fix broken links
2022-03-22 16:25:41 +00:00
Taus
f9120167b4 Python: Fix syntax error in with test output
Depends on an internal PR. The two lines in question were caused by
the insertion of an extra node due to the failure to parse a trailing
comma corrcetly.
2022-03-22 16:22:03 +00:00
Rasmus Wriedt Larsen
64a5c5d9aa Ruby: Keep getURL predicate for easier deprecation
Notice that we still don't fully keep our standard deprecation support,
since the new `getAUrlPart` is still abstract, and therefore will cause
compile errors if not implemented.
2022-03-22 16:48:14 +01:00
Paul1nh0
f2728f5284 delete some unused code 2022-03-22 23:20:30 +08:00
Chris Smowton
b5c05a580d Java: Fix harmless search-replace mistake 2022-03-22 14:42:09 +00:00
Mathias Vorreiter Pedersen
c35b385383 C++: Fix 'implicit this' warning. 2022-03-22 13:32:46 +00:00
Tom Hvitved
c06508570a Ruby: Cache ConstantReadAccess::getValue 2022-03-22 14:15:07 +01:00
Paul1nh0
afe4a8435f Using globalValueNumber to match same arguments 2022-03-22 21:14:07 +08:00
Chris Smowton
35af797683 Fix broken links 2022-03-22 12:34:22 +00:00
Mathias Vorreiter Pedersen
93346a574f C++: Add a new 'Location.isBefore' predicate that also considers columns. 2022-03-22 12:16:53 +00:00
Mathias Vorreiter Pedersen
c6c3206031 C++: Add example of 'goto' on the same line as the destination label. 2022-03-22 12:11:29 +00:00
Paul1nh0
d476493c3e Add double-fetch.ql under CWE-362 directory 2022-03-22 19:08:44 +08:00
Paul1nh0
dd4e82126c remove to another directory 2022-03-22 19:06:53 +08:00
Paul1nh0
2dad2c477b query description added 2022-03-22 19:06:03 +08:00
Mathias Vorreiter Pedersen
5cbd86519b C++: Add internal extraction errors query and modify the 'code-scanning-selectors' to exclude internal queries. 2022-03-22 10:52:02 +00:00
Michael Nebel
b95a332ded C#: Simplify the isCollectionType predicate. 2022-03-22 11:25:14 +01:00
Rasmus Wriedt Larsen
9254b2904e Ruby: Adjust HttpClients test 2022-03-22 11:19:55 +01:00
Rasmus Wriedt Larsen
945b52fc46 Ruby: autoformat
😳
2022-03-22 10:59:26 +01:00
Rasmus Wriedt Larsen
68de6a4e3c Ruby: Add change-note 2022-03-22 10:53:55 +01:00
Rasmus Wriedt Larsen
9c2fc1b415 Ruby: client request: getUrl => getAUrlPart
This is a port of the same change in Python from
f8fc583af3

The description of that commit was:

> I think `getUrl` is a bit too misleading, since from the name, I would
> only ever expect ONE result for one request being made.
>
> `getAUrlPart` captures that there could be multiple results, and that
> they might not constitute a whole URl.
>
> Which is the same naming I used when I tried to model this a long time ago
> a80860cdc6/python/ql/lib/semmle/python/web/Http.qll (L102-L111)
2022-03-22 10:53:55 +01:00
Rasmus Wriedt Larsen
311cbb4e13 Merge branch 'main' into shared-concepts-scaffolding 2022-03-22 10:36:33 +01:00
Rasmus Wriedt Larsen
414764ccee Concepts: Minor rewrite in qldoc
As suggested by @hmac
2022-03-22 10:33:58 +01:00
Rasmus Wriedt Larsen
e50a9421a6 JS: Update dataflow import in ConceptsImports.qll
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2022-03-22 10:32:20 +01:00
Tom Hvitved
99ddfb489f Ruby: Rework getConstantValue implementation 2022-03-22 10:07:44 +01:00
Harry Maclean
99b5c580a5 Ruby: Fix captured reads in lambdas
These were previously identified as method calls. The fix is to
recognise lambdas as a scope which can inherit variables from its
parent.
2022-03-22 15:35:43 +13:00
Harry Maclean
c891e62a0e Ruby: Add some tests for method calls in lambdas
This reveals a bug where we identify reads of captured variables in
lambdas as method calls. This is fixed in a followup commit.
2022-03-22 15:33:22 +13:00
Jeroen Ketema
2d9b630fa8 C++: Fix ExecTainted.ql formatting 2022-03-21 23:28:58 +01:00
Jeroen Ketema
b79eb6d10d C++: Encode string value of data flow nodes in ExecState 2022-03-21 21:29:42 +01:00
Michael Nebel
92f8a90f31 C#: Introduce a collectionType predicate. 2022-03-21 14:44:38 +01:00
Geoffrey White
97fef4b3a5 C++: Switch strategy to nomagic. 2022-03-21 12:58:06 +00:00
Ian Lynagh
7295a5d313 Java: Add an upgrade script 2022-03-21 11:51:36 +00:00
Ian Lynagh
6284362868 Java: Update stats 2022-03-21 11:44:19 +00:00
Jeroen Ketema
e05227d3fe C++: Add change note for the cpp/command-line-injection changes 2022-03-21 11:30:39 +01:00
Jeroen Ketema
8b4c42dd07 C++: Add cpp/command-line-injection test using a wrapper macro 2022-03-21 11:19:54 +01:00
Jeroen Ketema
f8198c3123 C++: Use flow states in cpp/command-line-injection 2022-03-18 20:06:45 +01:00
Erik Krogh Kristensen
693c77f3df add test for string replacement chains of URL schemes 2022-03-18 11:05:59 +01:00
Erik Krogh Kristensen
235aa9c24e recognize string replacement chains as scheme checks in js/incomplete-url-scheme-check 2022-03-18 10:37:20 +01:00
Geoffrey White
ff3bedcab9 C++: Fix expensive getWideCharType(). 2022-03-17 14:41:57 +00:00
Rasmus Wriedt Larsen
2b9408b0c3 Concepts: Add some architecture documentation 2022-03-17 13:49:10 +01:00
Harry Maclean
36c421346b Introduce ConceptsShared.qll 2022-03-17 13:49:10 +01:00
Ian Lynagh
565f607096 Java: Add a changenote for ErrorExpr/ErrorStmt 2022-03-16 13:20:33 +00:00
Geoffrey White
95a63a69a5 Merge branch 'main' into cwe497b 2022-03-16 11:09:46 +00:00
Paul1nh0
85b22647ac Add query for double-fetch vulnerability 2022-03-16 18:16:49 +08:00
Michael Nebel
8b16c1f585 C#: Add some test cases for inheritance. 2022-03-16 10:40:49 +01:00
Michael Nebel
e69ea8f577 C#: Add some testcases for generics. 2022-03-16 10:20:55 +01:00
Michael Nebel
814947b876 C#: Add some test cases for methods that are not properly exposed and will this not get their summary captured. 2022-03-16 09:47:14 +01:00
Michael Nebel
a555e04b55 C#: Bulk array flow. 2022-03-16 09:30:15 +01:00
Michael Nebel
226a874a74 C#: Test cases for IEnumerable. 2022-03-16 09:22:18 +01:00
Michael Nebel
ec6dab89d8 C#: Update the Summary model generator with better support for IEnumerable typed parameters. 2022-03-16 09:21:02 +01:00
Geoffrey White
92d748e006 C++: Fix ODR/dbcheck issue in test. 2022-03-15 20:00:19 +00:00
Ian Lynagh
2116e6d120 Java: Add ErrorExpr, ErrorStmt 2022-03-15 17:30:19 +00:00
Geoffrey White
46f3f28a11 C++: Fix broken merge. 2022-03-15 14:53:25 +00:00
Michael Nebel
4f2678fc72 C#: Add some testcases for model generation of methods using Lists. 2022-03-15 15:44:06 +01:00
Michael Nebel
a9bbe6889b C#: Use CollectionType instead of ArrayType when generating models. 2022-03-15 15:41:46 +01:00
Geoffrey White
71e0da738d Merge branch 'main' into cwe497b 2022-03-15 13:29:32 +00:00
Geoffrey White
28315df405 Merge branch 'main' into cwe497b 2022-03-15 11:23:00 +00:00
Geoffrey White
73710e9edb C++: Fix QLDoc. 2022-03-14 19:11:43 +00:00
Geoffrey White
7c93eb1eaf C++: Fix large newtype. 2022-03-14 19:06:41 +00:00
Geoffrey White
d1b04b4e07 C++: Use asDefiningArgument() where appropriate. 2022-03-14 17:53:47 +00:00
Geoffrey White
9ebdb2ac1d C++: QLDoc. 2022-03-08 16:12:58 +00:00
Geoffrey White
cb33ed4fc2 C++: Only look for sensitive strings in appropriate parameters. 2022-03-07 11:29:09 +00:00
Geoffrey White
f1d6234483 C++: Add more information about registry query parameters. 2022-03-07 09:45:31 +00:00
Geoffrey White
4316026720 C++: VariableAccess -> Expr. 2022-03-04 18:00:54 +00:00
Erik Krogh Kristensen
7691807713 delete the getLastParameter predicate from ApiGraphs 2022-03-04 16:24:54 +01:00
Erik Krogh Kristensen
934e06ca3b fix mistake in argumentPassing. The type-tracking was not required to be in an end state 2022-03-04 09:49:42 +01:00
Geoffrey White
6848b6095b C++: Autoformat. 2022-03-03 12:51:54 +00:00
Geoffrey White
5c6923c099 C++: Improve and differentiate the qhelp. 2022-03-03 11:04:55 +00:00
Geoffrey White
88b7a085b0 C++: Make the bulk of test cases in tests.cpp more relevant. 2022-03-03 10:40:17 +00:00
Geoffrey White
07b4bf7023 C++: Use the same trick as in ExposedSystemData to catch a few more results. 2022-03-03 10:33:39 +00:00
Geoffrey White
6e5729c924 C++: Fix typo and adjust violation message wording. 2022-03-03 10:28:53 +00:00
Geoffrey White
9e193f624c C++: Change note. 2022-03-03 09:55:02 +00:00
Geoffrey White
2a14a4f14e C++: Fill in metadata. 2022-03-02 18:52:52 +00:00
Geoffrey White
66b9356eb9 C++: There is no overlap between OutputWrite and RemoteFlowSinkFunction. 2022-03-02 18:16:39 +00:00
Geoffrey White
a1ace7122d C++: Move SystemData class into a library. 2022-03-02 18:01:06 +00:00
Geoffrey White
70e4a409fd C++: Add the new query to tests. 2022-03-02 17:56:53 +00:00
Geoffrey White
d95b56fca0 C++: Create prototype query. 2022-03-02 17:56:49 +00:00
Geoffrey White
67aa1449ce C++: Add some more test cases (moved from the private repo). 2022-03-02 17:23:07 +00:00
Geoffrey White
19718fa280 C++: Add a couple of new test cases. 2022-03-02 15:18:04 +00:00
Geoffrey White
da740cfa05 C++: Test layout. 2022-03-02 15:18:04 +00:00
Erik Krogh Kristensen
5130929358 remove comment suggesting that the receiver is parameter -1 2022-02-28 15:25:34 +01:00
Erik Krogh Kristensen
843ed8fca5 rename pw to aw
Co-authored-by: yoff <lerchedahl@gmail.com>
2022-02-28 15:25:25 +01:00
Erik Krogh Kristensen
5e23da813f rename named-parameters to keyword-parameters 2022-02-03 23:10:39 +01:00
Erik Krogh Kristensen
e434f075fa introduce, and use, API::APICallNode 2022-02-03 23:10:39 +01:00
Erik Krogh Kristensen
3801a158a8 remove module exporst nodes from API graphs 2022-02-03 23:10:39 +01:00
Erik Krogh Kristensen
c3f4a851f0 remove some TODOs I won't do 2022-02-03 23:10:39 +01:00
Erik Krogh Kristensen
3be3da2eb6 add recursive API-graph test 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
ef5818e243 support import * in ApiGraphs 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
16774ba285 add support for named parameters in API graphs 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
095c73f1fe redo the ApiGraph testing framework 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
66fd43fc3b add def edge for function returns 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
d8eea7ba4c property writes are def nodes 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
a908b219e9 more backtracking of def nodes, and lots of tests 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
038b032a43 get basic module exports to work in API-graphs 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
df9efbe778 get mimimal def nodes to work in python 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
52ca0d168b move API-graph tests out of the experimental test folder 2022-02-03 23:10:37 +01:00
Erik Krogh Kristensen
89786d9ce2 rename pr to ref in memberFromRef 2022-02-03 23:10:37 +01:00
224 changed files with 9974 additions and 3687 deletions

View File

@@ -16,9 +16,10 @@ jobs:
- uses: actions/checkout@v2
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@erik-krogh/ql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: javascript # does not matter
tools: latest
- name: Get CodeQL version
id: get-codeql-version
run: |
@@ -159,7 +160,7 @@ jobs:
PACK: ${{ runner.temp }}/pack
- name: Hack codeql-action options
run: |
JSON=$(jq -nc --arg pack "${PACK}" '.resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
echo "CODEQL_ACTION_EXTRA_OPTIONS=${JSON}" >> ${GITHUB_ENV}
env:
PACK: ${{ runner.temp }}/pack
@@ -171,22 +172,25 @@ jobs:
echo "paths:" > ${CONF}
echo " - ${FOLDER}" >> ${CONF}
echo "paths-ignore:" >> ${CONF}
echo " - ql/ql/test" >> ${CONF}
echo " - ql/ql/test" >> ${CONF}
echo "disable-default-queries: true" >> ${CONF}
echo "packs:" >> ${CONF}
echo " - codeql/ql" >> ${CONF}
echo "Config file: "
cat ${CONF}
env:
CONF: ./ql-for-ql-config.yml
FOLDER: ${{ matrix.folder }}
- name: Initialize CodeQL
uses: github/codeql-action/init@erik-krogh/ql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: ql
db-location: ${{ runner.temp }}/db
config-file: ./ql-for-ql-config.yml
tools: latest
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@erik-krogh/ql
uses: github/codeql-action/analyze@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
category: "ql-for-ql-${{ matrix.folder }}"
- name: Copy sarif file to CWD

View File

@@ -26,7 +26,7 @@ jobs:
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@erik-krogh/ql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: javascript # does not matter
- uses: actions/cache@v2

View File

@@ -20,7 +20,7 @@ jobs:
- uses: actions/checkout@v2
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@erik-krogh/ql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: javascript # does not matter
- uses: actions/cache@v2

View File

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

View File

@@ -519,6 +519,11 @@
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll"
],
"Concepts Python/Ruby/JS": [
"python/ql/lib/semmle/python/internal/ConceptsShared.qll",
"ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll",
"javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll"
],
"Hostname Regexp queries": [
"javascript/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
"python/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
@@ -544,4 +549,4 @@
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
]
}
}

View File

@@ -73,8 +73,24 @@ class Location extends @location {
/** Holds if `this` comes on a line strictly before `l`. */
pragma[inline]
predicate isBefore(Location l) {
this.getFile() = l.getFile() and this.getEndLine() < l.getStartLine()
predicate isBefore(Location l) { this.isBefore(l, false) }
/**
* Holds if `this` comes strictly before `l`. The boolean `sameLine` is
* true if `l` is on the same line as `this`, but starts at a later column.
* Otherwise, `sameLine` is false.
*/
pragma[inline]
predicate isBefore(Location l, boolean sameLine) {
this.getFile() = l.getFile() and
(
sameLine = false and
this.getEndLine() < l.getStartLine()
or
sameLine = true and
this.getEndLine() = l.getStartLine() and
this.getEndColumn() < l.getStartColumn()
)
}
/** Holds if location `l` is completely contained within this one. */

View File

@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
this.dominates(result.getAPredecessor()) and
not this.strictlyDominates(result)
this.getASuccessor() = result and
not this.immediatelyDominates(result)
or
exists(IRBlock prev | result = prev.dominanceFrontier() |
this.immediatelyDominates(prev) and
not this.immediatelyDominates(result)
)
}
/**
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock postDominanceFrontier() {
this.postDominates(result.getASuccessor()) and
not this.strictlyPostDominates(result)
this.getAPredecessor() = result and
not this.immediatelyPostDominates(result)
or
exists(IRBlock prev | result = prev.postDominanceFrontier() |
this.immediatelyPostDominates(prev) and
not this.immediatelyPostDominates(result)
)
}
/**

View File

@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
this.dominates(result.getAPredecessor()) and
not this.strictlyDominates(result)
this.getASuccessor() = result and
not this.immediatelyDominates(result)
or
exists(IRBlock prev | result = prev.dominanceFrontier() |
this.immediatelyDominates(prev) and
not this.immediatelyDominates(result)
)
}
/**
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock postDominanceFrontier() {
this.postDominates(result.getASuccessor()) and
not this.strictlyPostDominates(result)
this.getAPredecessor() = result and
not this.immediatelyPostDominates(result)
or
exists(IRBlock prev | result = prev.postDominanceFrontier() |
this.immediatelyPostDominates(prev) and
not this.immediatelyPostDominates(result)
)
}
/**

View File

@@ -349,7 +349,7 @@ Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind ki
/** Holds if `goto` jumps strictly forward in the program text. */
private predicate isStrictlyForwardGoto(GotoStmt goto) {
goto.getLocation().isBefore(goto.getTarget().getLocation())
goto.getLocation().isBefore(goto.getTarget().getLocation(), _)
}
Locatable getInstructionAst(TStageInstruction instr) {

View File

@@ -154,13 +154,6 @@ private predicate ignoreSideEffects(Expr expr) {
* around extractor bugs. Once the relevant extractor bugs are fixed, this predicate can be removed.
*/
private predicate isInvalidFunction(Function func) {
exists(Literal literal |
// Constructor field inits within a compiler-generated copy constructor have a source expression
// that is a `Literal` with no value.
literal = func.(Constructor).getAnInitializer().(ConstructorFieldInit).getExpr() and
not exists(literal.getValue())
)
or
exists(ThisExpr thisExpr |
// An instantiation of a member function template is not treated as a `MemberFunction` if it has
// only non-type template arguments.

View File

@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
this.dominates(result.getAPredecessor()) and
not this.strictlyDominates(result)
this.getASuccessor() = result and
not this.immediatelyDominates(result)
or
exists(IRBlock prev | result = prev.dominanceFrontier() |
this.immediatelyDominates(prev) and
not this.immediatelyDominates(result)
)
}
/**
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock postDominanceFrontier() {
this.postDominates(result.getASuccessor()) and
not this.strictlyPostDominates(result)
this.getAPredecessor() = result and
not this.immediatelyPostDominates(result)
or
exists(IRBlock prev | result = prev.postDominanceFrontier() |
this.immediatelyPostDominates(prev) and
not this.immediatelyPostDominates(result)
)
}
/**

View File

@@ -92,6 +92,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
* snapshots there may be multiple results where we can't tell which is correct for a
* particular function.
*/
pragma[nomagic]
Type getWideCharType() {
result = getFormatCharType() and
result.getSize() > 1

View File

@@ -0,0 +1,21 @@
/**
* @name Extraction errors
* @description List all extraction errors for files in the source code directory.
* @kind diagnostic
* @id cpp/diagnostics/extraction-errors
*/
import cpp
import ExtractionErrors
// NOTE:
// This file looks like the other `diagnostics/extraction-errors` queries in other CodeQL supported
// languages. However, since this diagnostic query is located in the `Internal` subdirectory it will not
// appear in the Code Scanning suite. The related query `cpp/diagnostics/extraction-warnings` is,
// however, included as a public diagnostics query.
from ExtractionError error
where
error instanceof ExtractionUnknownError or
exists(error.getFile().getRelativePath())
select error, "Extraction failed in " + error.getFile() + " with error " + error.getErrorMessage(),
error.getSeverity()

View File

@@ -0,0 +1,137 @@
/**
* Provides a common hierarchy of all types of errors that can occur during extraction.
*/
import cpp
/*
* A note about how the C/C++ extractor emits diagnostics:
* When the extractor frontend encounters an error, it emits a diagnostic message,
* that includes a message, location and severity.
* However, that process is best-effort and may fail (e.g. due to lack of memory).
* Thus, if the extractor emitted at least one diagnostic of severity discretionary
* error (or higher), it *also* emits a simple "There was an error during this compilation"
* error diagnostic, without location information.
* In the common case, this means that a compilation during which one or more errors happened also gets
* the catch-all diagnostic.
* This diagnostic has the empty string as file path.
* We filter out these useless diagnostics if there is at least one error-level diagnostic
* for the affected compilation in the database.
* Otherwise, we show it to indicate that something went wrong and that we
* don't know what exactly happened.
*/
/**
* An error that, if present, leads to a file being marked as non-successfully extracted.
*/
class ReportableError extends Diagnostic {
ReportableError() {
(
this instanceof CompilerDiscretionaryError or
this instanceof CompilerError or
this instanceof CompilerCatastrophe
) and
// Filter for the catch-all diagnostic, see note above.
not this.getFile().getAbsolutePath() = ""
}
}
private newtype TExtractionError =
TReportableError(ReportableError err) or
TCompilationFailed(Compilation c, File f) {
f = c.getAFileCompiled() and not c.normalTermination()
} or
// Show the catch-all diagnostic (see note above) only if we haven't seen any other error-level diagnostic
// for that compilation
TUnknownError(CompilerError err) {
not exists(ReportableError e | e.getCompilation() = err.getCompilation())
}
/**
* Superclass for the extraction error hierarchy.
*/
class ExtractionError extends TExtractionError {
/** Gets the string representation of the error. */
string toString() { none() }
/** Gets the error message for this error. */
string getErrorMessage() { none() }
/** Gets the file this error occured in. */
File getFile() { none() }
/** Gets the location this error occured in. */
Location getLocation() { none() }
/** Gets the SARIF severity of this error. */
int getSeverity() {
// Unfortunately, we can't distinguish between errors and fatal errors in SARIF,
// so all errors have severity 2.
result = 2
}
}
/**
* An unrecoverable extraction error, where extraction was unable to finish.
* This can be caused by a multitude of reasons, for example:
* - hitting a frontend assertion
* - crashing due to dereferencing an invalid pointer
* - stack overflow
* - out of memory
*/
class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed {
Compilation c;
File f;
ExtractionUnrecoverableError() { this = TCompilationFailed(c, f) }
override string toString() {
result = "Unrecoverable extraction error while compiling " + f.toString()
}
override string getErrorMessage() { result = "unrecoverable compilation failure." }
override File getFile() { result = f }
override Location getLocation() { result = f.getLocation() }
}
/**
* A recoverable extraction error.
* These are compiler errors from the frontend.
* Upon encountering one of these, we still continue extraction, but the
* database will be incomplete for that file.
*/
class ExtractionRecoverableError extends ExtractionError, TReportableError {
ReportableError err;
ExtractionRecoverableError() { this = TReportableError(err) }
override string toString() { result = "Recoverable extraction error: " + err }
override string getErrorMessage() { result = err.getFullMessage() }
override File getFile() { result = err.getFile() }
override Location getLocation() { result = err.getLocation() }
}
/**
* An unknown error happened during extraction.
* These are only displayed if we know that we encountered an error during extraction,
* but, for some reason, failed to emit a proper diagnostic with location information
* and error message.
*/
class ExtractionUnknownError extends ExtractionError, TUnknownError {
CompilerError err;
ExtractionUnknownError() { this = TUnknownError(err) }
override string toString() { result = "Unknown extraction error: " + err }
override string getErrorMessage() { result = err.getFullMessage() }
override File getFile() { result = err.getFile() }
override Location getLocation() { result = err.getLocation() }
}

View File

@@ -19,9 +19,9 @@ import semmle.code.cpp.security.Security
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.dataflow.TaintTracking2
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.models.implementations.Strcat
import DataFlow::PathGraph
Expr sinkAsArgumentIndirection(DataFlow::Node sink) {
result =
@@ -66,154 +66,70 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
)
}
class TaintToConcatenationConfiguration extends TaintTracking::Configuration {
TaintToConcatenationConfiguration() { this = "TaintToConcatenationConfiguration" }
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSink(DataFlow::Node sink) { interestingConcatenation(sink, _) }
override predicate isSanitizer(DataFlow::Node node) {
node.asInstruction().getResultType() instanceof IntegralType
or
node.asInstruction().getResultType() instanceof FloatingPointType
}
class ConcatState extends DataFlow::FlowState {
ConcatState() { this = "ConcatState" }
}
class ExecTaintConfiguration extends TaintTracking2::Configuration {
class ExecState extends DataFlow::FlowState {
DataFlow::Node fst;
DataFlow::Node snd;
ExecState() {
this =
"ExecState (" + fst.getLocation() + " | " + fst + ", " + snd.getLocation() + " | " + snd + ")" and
interestingConcatenation(fst, snd)
}
DataFlow::Node getFstNode() { result = fst }
DataFlow::Node getSndNode() { result = snd }
}
class ExecTaintConfiguration extends TaintTracking::Configuration {
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
override predicate isSource(DataFlow::Node source) {
exists(DataFlow::Node prevSink, TaintToConcatenationConfiguration conf |
conf.hasFlow(_, prevSink) and
interestingConcatenation(prevSink, source)
)
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
source instanceof FlowSource and
state instanceof ConcatState
}
override predicate isSink(DataFlow::Node sink) {
shellCommand(sinkAsArgumentIndirection(sink), _)
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
shellCommand(sinkAsArgumentIndirection(sink), _) and
state instanceof ExecState
}
override predicate isSanitizerOut(DataFlow::Node node) {
isSink(node) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
}
}
module StitchedPathGraph {
// There's a different PathNode class for each DataFlowImplN.qll, so we can't simply combine the
// PathGraph predicates directly. Instead, we use a newtype so there's a single type that
// contains both sets of PathNodes.
newtype TMergedPathNode =
TPathNode1(DataFlow::PathNode node) or
TPathNode2(DataFlow2::PathNode node)
// this wraps the toString and location predicates so we can use the merged node type in a
// selection
class MergedPathNode extends TMergedPathNode {
string toString() {
exists(DataFlow::PathNode n |
this = TPathNode1(n) and
result = n.toString()
)
or
exists(DataFlow2::PathNode n |
this = TPathNode2(n) and
result = n.toString()
)
}
DataFlow::Node getNode() {
exists(DataFlow::PathNode n |
this = TPathNode1(n) and
result = n.getNode()
)
or
exists(DataFlow2::PathNode n |
this = TPathNode2(n) and
result = n.getNode()
)
}
DataFlow::PathNode getPathNode1() { this = TPathNode1(result) }
DataFlow2::PathNode getPathNode2() { this = TPathNode2(result) }
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(DataFlow::PathNode n |
this = TPathNode1(n) and
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
or
exists(DataFlow2::PathNode n |
this = TPathNode2(n) and
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
}
}
query predicate edges(MergedPathNode a, MergedPathNode b) {
exists(DataFlow::PathNode an, DataFlow::PathNode bn |
a = TPathNode1(an) and
b = TPathNode1(bn) and
DataFlow::PathGraph::edges(an, bn)
)
or
exists(DataFlow2::PathNode an, DataFlow2::PathNode bn |
a = TPathNode2(an) and
b = TPathNode2(bn) and
DataFlow2::PathGraph::edges(an, bn)
)
or
// This is where paths from the two configurations are connected. `interestingConcatenation`
// is the only thing in this module that's actually specific to the query - everything else is
// just using types and predicates from the DataFlow library.
interestingConcatenation(a.getNode(), b.getNode()) and
a instanceof TPathNode1 and
b instanceof TPathNode2
}
query predicate nodes(MergedPathNode mpn, string key, string val) {
// here we just need the union of the underlying `nodes` predicates
exists(DataFlow::PathNode n |
mpn = TPathNode1(n) and
DataFlow::PathGraph::nodes(n, key, val)
)
or
exists(DataFlow2::PathNode n |
mpn = TPathNode2(n) and
DataFlow2::PathGraph::nodes(n, key, val)
)
}
query predicate subpaths(
MergedPathNode arg, MergedPathNode par, MergedPathNode ret, MergedPathNode out
override predicate isAdditionalTaintStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
// just forward subpaths from the underlying libraries. This might be slightly awkward when
// the concatenation is deep in a call chain.
DataFlow::PathGraph::subpaths(arg.getPathNode1(), par.getPathNode1(), ret.getPathNode1(),
out.getPathNode1())
or
DataFlow2::PathGraph::subpaths(arg.getPathNode2(), par.getPathNode2(), ret.getPathNode2(),
out.getPathNode2())
state1 instanceof ConcatState and
state2.(ExecState).getFstNode() = node1 and
state2.(ExecState).getSndNode() = node2
}
override predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) {
(
node.asInstruction().getResultType() instanceof IntegralType
or
node.asInstruction().getResultType() instanceof FloatingPointType
) and
state instanceof ConcatState
}
override predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) {
isSink(node, state) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
}
}
import StitchedPathGraph
from
DataFlow::PathNode sourceNode, DataFlow::PathNode concatSink, DataFlow2::PathNode concatSource,
DataFlow2::PathNode sinkNode, string taintCause, string callChain,
TaintToConcatenationConfiguration conf1, ExecTaintConfiguration conf2
ExecTaintConfiguration conf, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode,
string taintCause, string callChain, DataFlow::Node concatResult
where
conf.hasFlowPath(sourceNode, sinkNode) and
taintCause = sourceNode.getNode().(FlowSource).getSourceType() and
conf1.hasFlowPath(sourceNode, concatSink) and
interestingConcatenation(concatSink.getNode(), concatSource.getNode()) and // this loses call context
conf2.hasFlowPath(concatSource, sinkNode) and
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain)
select sinkAsArgumentIndirection(sinkNode.getNode()), TPathNode1(sourceNode).(MergedPathNode),
TPathNode2(sinkNode).(MergedPathNode),
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain) and
concatResult = sinkNode.getState().(ExecState).getSndNode()
select sinkAsArgumentIndirection(sinkNode.getNode()), sourceNode, sinkNode,
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
+ callChain, sourceNode, "user input (" + taintCause + ")", concatSource,
concatSource.toString()
+ callChain, sourceNode, "user input (" + taintCause + ")", concatResult,
concatResult.toString()

View File

@@ -3,17 +3,17 @@
"qhelp.dtd">
<qhelp>
<overview>
<p>Exposing system data or debugging information may help an adversary to learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in these technologies.</p>
<p>Exposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.</p>
<p>This query finds locations where system configuration information might be revealed to a user.</p>
<p>This query finds locations where system configuration information might be revealed to a remote user.</p>
</overview>
<recommendation>
<p>Do not expose system configuration information to users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to an adversary.</p>
<p>Do not expose system configuration information to remote users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.</p>
</recommendation>
<example>
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to an adversary who does not have legitimate access to that information.</p>
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.</p>
<sample src="ExposedSystemDataIncorrect.cpp" />

View File

@@ -1,7 +1,7 @@
/**
* @name Exposure of system data to an unauthorized control sphere
* @description Exposing system data or debugging information helps
* an adversary learn about the system and form an
* a malicious user learn about the system and form an
* attack plan.
* @kind path-problem
* @problem.severity warning
@@ -13,284 +13,15 @@
*/
import cpp
import semmle.code.cpp.commons.Environment
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.FlowSource
import DataFlow::PathGraph
/**
* An element that should not be exposed to an adversary.
*/
abstract class SystemData extends Element {
/**
* Gets an expression that is part of this `SystemData`.
*/
abstract Expr getAnExpr();
}
/**
* Data originating from the environment.
*/
class EnvData extends SystemData {
EnvData() {
// identify risky looking environment variables only
this.(EnvironmentRead)
.getEnvironmentVariable()
.toLowerCase()
.regexpMatch(".*(user|host|admin|root|home|path|http|ssl|snmp|sock|port|proxy|pass|token|crypt|key).*")
}
override Expr getAnExpr() { result = this }
}
/**
* Data originating from a call to `mysql_get_client_info()`.
*/
class SqlClientInfo extends SystemData {
SqlClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
override Expr getAnExpr() { result = this }
}
private predicate sqlConnectInfo(FunctionCall source, VariableAccess use) {
(
source.getTarget().hasName("mysql_connect") or
source.getTarget().hasName("mysql_real_connect")
) and
use = source.getAnArgument()
}
/**
* Data passed into an SQL connect function.
*/
class SqlConnectInfo extends SystemData {
SqlConnectInfo() { sqlConnectInfo(this, _) }
override Expr getAnExpr() { sqlConnectInfo(this, result) }
}
private predicate posixSystemInfo(FunctionCall source, Element use) {
// size_t confstr(int name, char *buf, size_t len)
// - various OS / system strings, such as the libc version
// int statvfs(const char *__path, struct statvfs *__buf)
// int fstatvfs(int __fd, struct statvfs *__buf)
// - various filesystem parameters
// int uname(struct utsname *buf)
// - OS name and version
source.getTarget().hasName(["confstr", "statvfs", "fstatvfs", "uname"]) and
use = source.getArgument(1)
}
/**
* Data obtained from a POSIX system information call.
*/
class PosixSystemInfo extends SystemData {
PosixSystemInfo() { posixSystemInfo(this, _) }
override Expr getAnExpr() { posixSystemInfo(this, result) }
}
private predicate posixPWInfo(FunctionCall source, Element use) {
// struct passwd *getpwnam(const char *name);
// struct passwd *getpwuid(uid_t uid);
// struct passwd *getpwent(void);
// struct group *getgrnam(const char *name);
// struct group *getgrgid(gid_t);
// struct group *getgrent(void);
source
.getTarget()
.hasName(["getpwnam", "getpwuid", "getpwent", "getgrnam", "getgrgid", "getgrent"]) and
use = source
or
// int getpwnam_r(const char *name, struct passwd *pwd,
// char *buf, size_t buflen, struct passwd **result);
// int getpwuid_r(uid_t uid, struct passwd *pwd,
// char *buf, size_t buflen, struct passwd **result);
// int getgrgid_r(gid_t gid, struct group *grp,
// char *buf, size_t buflen, struct group **result);
// int getgrnam_r(const char *name, struct group *grp,
// char *buf, size_t buflen, struct group **result);
source.getTarget().hasName(["getpwnam_r", "getpwuid_r", "getgrgid_r", "getgrnam_r"]) and
use = source.getArgument([1, 2, 4])
or
// int getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
// struct passwd **result);
// int getgrent_r(struct group *gbuf, char *buf,
// size_t buflen, struct group **gbufp);
source.getTarget().hasName(["getpwent_r", "getgrent_r"]) and
use = source.getArgument([0, 1, 3])
}
/**
* Data obtained from a POSIX user/password/group database information call.
*/
class PosixPWInfo extends SystemData {
PosixPWInfo() { posixPWInfo(this, _) }
override Expr getAnExpr() { posixPWInfo(this, result) }
}
private predicate windowsSystemInfo(FunctionCall source, Element use) {
// DWORD WINAPI GetVersion(void);
source.getTarget().hasGlobalName("GetVersion") and
use = source
or
// BOOL WINAPI GetVersionEx(_Inout_ LPOSVERSIONINFO lpVersionInfo);
// void WINAPI GetSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
// void WINAPI GetNativeSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
source
.getTarget()
.hasGlobalName([
"GetVersionEx", "GetVersionExA", "GetVersionExW", "GetSystemInfo", "GetNativeSystemInfo"
]) and
use = source.getArgument(0)
}
/**
* Data obtained from a Windows system information call.
*/
class WindowsSystemInfo extends SystemData {
WindowsSystemInfo() { windowsSystemInfo(this, _) }
override Expr getAnExpr() { windowsSystemInfo(this, result) }
}
private predicate windowsFolderPath(FunctionCall source, Element use) {
// BOOL SHGetSpecialFolderPath(
// HWND hwndOwner,
// _Out_ LPTSTR lpszPath,
// _In_ int csidl,
// _In_ BOOL fCreate
// );
source
.getTarget()
.hasGlobalName([
"SHGetSpecialFolderPath", "SHGetSpecialFolderPathA", "SHGetSpecialFolderPathW"
]) and
use = source.getArgument(1)
or
// HRESULT SHGetKnownFolderPath(
// _In_ REFKNOWNFOLDERID rfid,
// _In_ DWORD dwFlags,
// _In_opt_ HANDLE hToken,
// _Out_ PWSTR *ppszPath
// );
source.getTarget().hasGlobalName("SHGetKnownFolderPath") and
use = source.getArgument(3)
or
// HRESULT SHGetFolderPath(
// _In_ HWND hwndOwner,
// _In_ int nFolder,
// _In_ HANDLE hToken,
// _In_ DWORD dwFlags,
// _Out_ LPTSTR pszPath
// );
source.getTarget().hasGlobalName(["SHGetFolderPath", "SHGetFolderPathA", "SHGetFolderPathW"]) and
use = source.getArgument(4)
or
// HRESULT SHGetFolderPathAndSubDir(
// _In_ HWND hwnd,
// _In_ int csidl,
// _In_ HANDLE hToken,
// _In_ DWORD dwFlags,
// _In_ LPCTSTR pszSubDir,
// _Out_ LPTSTR pszPath
// );
source
.getTarget()
.hasGlobalName([
"SHGetFolderPathAndSubDir", "SHGetFolderPathAndSubDirA", "SHGetFolderPathAndSubDirW"
]) and
use = source.getArgument(5)
}
/**
* Data obtained about Windows special paths (for example, the
* location of `System32`).
*/
class WindowsFolderPath extends SystemData {
WindowsFolderPath() { windowsFolderPath(this, _) }
override Expr getAnExpr() { windowsFolderPath(this, result) }
}
private predicate logonUser(FunctionCall source, VariableAccess use) {
source.getTarget().hasGlobalName(["LogonUser", "LogonUserW", "LogonUserA"]) and
use = source.getAnArgument()
}
/**
* Data passed into a `LogonUser` (Windows) function.
*/
class LogonUser extends SystemData {
LogonUser() { logonUser(this, _) }
override Expr getAnExpr() { logonUser(this, result) }
}
private predicate regQuery(FunctionCall source, VariableAccess use) {
// LONG WINAPI RegQueryValue(
// _In_ HKEY hKey,
// _In_opt_ LPCTSTR lpSubKey,
// _Out_opt_ LPTSTR lpValue,
// _Inout_opt_ PLONG lpcbValue
// );
source.getTarget().hasGlobalName(["RegQueryValue", "RegQueryValueA", "RegQueryValueW"]) and
use = source.getArgument(2)
or
// LONG WINAPI RegQueryMultipleValues(
// _In_ HKEY hKey,
// _Out_ PVALENT val_list,
// _In_ DWORD num_vals,
// _Out_opt_ LPTSTR lpValueBuf,
// _Inout_opt_ LPDWORD ldwTotsize
// );
source
.getTarget()
.hasGlobalName([
"RegQueryMultipleValues", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW"
]) and
use = source.getArgument(3)
or
// LONG WINAPI RegQueryValueEx(
// _In_ HKEY hKey,
// _In_opt_ LPCTSTR lpValueName,
// _Reserved_ LPDWORD lpReserved,
// _Out_opt_ LPDWORD lpType,
// _Out_opt_ LPBYTE lpData,
// _Inout_opt_ LPDWORD lpcbData
// );
source.getTarget().hasGlobalName(["RegQueryValueEx", "RegQueryValueExA", "RegQueryValueExW"]) and
use = source.getArgument(4)
or
// LONG WINAPI RegGetValue(
// _In_ HKEY hkey,
// _In_opt_ LPCTSTR lpSubKey,
// _In_opt_ LPCTSTR lpValue,
// _In_opt_ DWORD dwFlags,
// _Out_opt_ LPDWORD pdwType,
// _Out_opt_ PVOID pvData,
// _Inout_opt_ LPDWORD pcbData
// );
source.getTarget().hasGlobalName(["RegGetValue", "RegGetValueA", "RegGetValueW"]) and
use = source.getArgument(5)
}
/**
* Data read from the Windows registry.
*/
class RegQuery extends SystemData {
RegQuery() { regQuery(this, _) }
override Expr getAnExpr() { regQuery(this, result) }
}
import SystemData
class ExposedSystemDataConfiguration extends TaintTracking::Configuration {
ExposedSystemDataConfiguration() { this = "ExposedSystemDataConfiguration" }
override predicate isSource(DataFlow::Node source) {
source.asConvertedExpr() = any(SystemData sd).getAnExpr()
}
override predicate isSource(DataFlow::Node source) { source = any(SystemData sd).getAnExpr() }
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc, FunctionInput input, int arg |

View File

@@ -2,6 +2,5 @@ char* path = getenv("PATH");
//...
fprintf(stderr, "A required executable file could not be found. " \
"Please ensure that the software has been installed " \
"correctly or contact a system administrator.\n");
message = "An internal error has occurred. Please try again or contact a system administrator.\n";
send(socket, message, strlen(message), 0);

View File

@@ -2,4 +2,5 @@ char* path = getenv("PATH");
//...
fprintf(stderr, "cannot find exe on path %s\n", path);
sprintf(buffer, "Cannot find exe on path: %s", path);
send(socket, buffer, strlen(buffer), 0);

View File

@@ -0,0 +1,28 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Exposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.</p>
<p>This query finds locations where system configuration information that is particularly sensitive might be revealed to a user.</p>
</overview>
<recommendation>
<p>Do not expose system configuration information to users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.</p>
</recommendation>
<example>
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.</p>
<sample src="PotentiallyExposedSystemDataIncorrect.cpp" />
<p>The message should be rephrased without this information, for example:</p>
<sample src="PotentiallyExposedSystemDataCorrect.cpp" />
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,51 @@
/**
* @name Potential exposure of sensitive system data to an unauthorized control sphere
* @description Exposing sensitive system data helps
* a malicious user learn about the system and form an
* attack plan.
* @kind path-problem
* @problem.severity warning
* @security-severity 6.5
* @precision medium
* @id cpp/potential-system-data-exposure
* @tags security
* external/cwe/cwe-497
*/
/*
* These queries are closely related:
* - `cpp/system-data-exposure`, which flags exposure of system information
* to a remote sink (i.e. focusses on quality of the sink).
* - `cpp/potential-system-data-exposure`, which flags on exposure of the most
* sensitive information to a local sink (i.e. focusses on quality of the
* sensitive information).
*
* This used to be a single query with neither focus, which was too noisy and
* gave the user less control.
*/
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.FlowSource
import semmle.code.cpp.security.OutputWrite
import DataFlow::PathGraph
import SystemData
class PotentiallyExposedSystemDataConfiguration extends TaintTracking::Configuration {
PotentiallyExposedSystemDataConfiguration() { this = "PotentiallyExposedSystemDataConfiguration" }
override predicate isSource(DataFlow::Node source) {
source = any(SystemData sd | sd.isSensitive()).getAnExpr()
}
override predicate isSink(DataFlow::Node sink) {
exists(OutputWrite ow | ow.getASource().getAChild*() = sink.asExpr())
}
}
from
PotentiallyExposedSystemDataConfiguration config, DataFlow::PathNode source,
DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink, source, sink, "This operation potentially exposes sensitive system data from $@.",
source, source.getNode().toString()

View File

@@ -0,0 +1,5 @@
char* key = getenv("APP_KEY");
//...
fprintf(stderr, "Application key not recognized. Please ensure the key is correct or contact a system administrator.\n", key);

View File

@@ -0,0 +1,5 @@
char* key = getenv("APP_KEY");
//...
fprintf(stderr, "Key not recognized: %s\n", key);

View File

@@ -0,0 +1,342 @@
/**
* Classes for recognizing system data, used by the exposed system data queries.
*/
import cpp
import semmle.code.cpp.commons.Environment
import semmle.code.cpp.ir.dataflow.TaintTracking
/**
* An element that should not be exposed to a malicious user.
*/
abstract class SystemData extends Element {
/**
* Gets an expression that is part of this `SystemData`.
*/
abstract DataFlow::Node getAnExpr();
/**
* Holds if this system data is considered especially sensitive (for example
* a password or token).
*/
predicate isSensitive() { none() }
}
/**
* Data originating from the environment.
*/
class EnvData extends SystemData {
EnvData() {
// identify risky looking environment variables only
this.(EnvironmentRead)
.getEnvironmentVariable()
.toLowerCase()
.regexpMatch(".*(user|host|admin|root|home|path|http|ssl|snmp|sock|port|proxy|pass|token|crypt|key).*")
}
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
override predicate isSensitive() {
this.(EnvironmentRead)
.getEnvironmentVariable()
.toLowerCase()
.regexpMatch(".*(pass|token|key).*")
}
}
/**
* Data originating from a call to `mysql_get_client_info()`.
*/
class SQLClientInfo extends SystemData {
SQLClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
override predicate isSensitive() { any() }
}
private predicate sqlConnectInfo(FunctionCall source, Expr use) {
(
source.getTarget().hasName("mysql_connect") or
source.getTarget().hasName("mysql_real_connect")
) and
use = source.getAnArgument()
}
/**
* Data passed into an SQL connect function.
*/
class SQLConnectInfo extends SystemData {
SQLConnectInfo() { sqlConnectInfo(this, _) }
override DataFlow::Node getAnExpr() { sqlConnectInfo(this, result.asConvertedExpr()) }
override predicate isSensitive() { any() }
}
private predicate posixSystemInfo(FunctionCall source, DataFlow::Node use) {
// size_t confstr(int name, char *buf, size_t len)
// - various OS / system strings, such as the libc version
// int statvfs(const char *__path, struct statvfs *__buf)
// int fstatvfs(int __fd, struct statvfs *__buf)
source.getTarget().hasName(["confstr", "statvfs", "fstatvfs"]) and
use.asDefiningArgument() = source.getArgument(1)
or
// - various filesystem parameters
// int uname(struct utsname *buf)
// - OS name and version
source.getTarget().hasName("uname") and
use.asDefiningArgument() = source.getArgument(0)
}
/**
* Data obtained from a POSIX system information call.
*/
class PosixSystemInfo extends SystemData {
PosixSystemInfo() { posixSystemInfo(this, _) }
override DataFlow::Node getAnExpr() { posixSystemInfo(this, result) }
}
private predicate posixPWInfo(FunctionCall source, DataFlow::Node use) {
// struct passwd *getpwnam(const char *name);
// struct passwd *getpwuid(uid_t uid);
// struct passwd *getpwent(void);
// struct group *getgrnam(const char *name);
// struct group *getgrgid(gid_t);
// struct group *getgrent(void);
source
.getTarget()
.hasName(["getpwnam", "getpwuid", "getpwent", "getgrnam", "getgrgid", "getgrent"]) and
use.asConvertedExpr() = source
or
// int getpwnam_r(const char *name, struct passwd *pwd,
// char *buf, size_t buflen, struct passwd **result);
// int getpwuid_r(uid_t uid, struct passwd *pwd,
// char *buf, size_t buflen, struct passwd **result);
// int getgrgid_r(gid_t gid, struct group *grp,
// char *buf, size_t buflen, struct group **result);
// int getgrnam_r(const char *name, struct group *grp,
// char *buf, size_t buflen, struct group **result);
source.getTarget().hasName(["getpwnam_r", "getpwuid_r", "getgrgid_r", "getgrnam_r"]) and
(
use.asConvertedExpr() = source.getArgument([1, 2]) or
use.asDefiningArgument() = source.getArgument(4)
)
or
// int getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
// struct passwd **result);
// int getgrent_r(struct group *gbuf, char *buf,
// size_t buflen, struct group **gbufp);
source.getTarget().hasName(["getpwent_r", "getgrent_r"]) and
(
use.asConvertedExpr() = source.getArgument([0, 1]) or
use.asDefiningArgument() = source.getArgument(3)
)
}
/**
* Data obtained from a POSIX user/password/group database information call.
*/
class PosixPWInfo extends SystemData {
PosixPWInfo() { posixPWInfo(this, _) }
override DataFlow::Node getAnExpr() { posixPWInfo(this, result) }
override predicate isSensitive() { any() }
}
private predicate windowsSystemInfo(FunctionCall source, DataFlow::Node use) {
// DWORD WINAPI GetVersion(void);
source.getTarget().hasGlobalName("GetVersion") and
use.asConvertedExpr() = source
or
// BOOL WINAPI GetVersionEx(_Inout_ LPOSVERSIONINFO lpVersionInfo);
// void WINAPI GetSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
// void WINAPI GetNativeSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
source
.getTarget()
.hasGlobalName([
"GetVersionEx", "GetVersionExA", "GetVersionExW", "GetSystemInfo", "GetNativeSystemInfo"
]) and
use.asDefiningArgument() = source.getArgument(0)
}
/**
* Data obtained from a Windows system information call.
*/
class WindowsSystemInfo extends SystemData {
WindowsSystemInfo() { windowsSystemInfo(this, _) }
override DataFlow::Node getAnExpr() { windowsSystemInfo(this, result) }
}
private predicate windowsFolderPath(FunctionCall source, Element use) {
// BOOL SHGetSpecialFolderPath(
// HWND hwndOwner,
// _Out_ LPTSTR lpszPath,
// _In_ int csidl,
// _In_ BOOL fCreate
// );
source
.getTarget()
.hasGlobalName([
"SHGetSpecialFolderPath", "SHGetSpecialFolderPathA", "SHGetSpecialFolderPathW"
]) and
use = source.getArgument(1)
or
// HRESULT SHGetKnownFolderPath(
// _In_ REFKNOWNFOLDERID rfid,
// _In_ DWORD dwFlags,
// _In_opt_ HANDLE hToken,
// _Out_ PWSTR *ppszPath
// );
source.getTarget().hasGlobalName("SHGetKnownFolderPath") and
use = source.getArgument(3)
or
// HRESULT SHGetFolderPath(
// _In_ HWND hwndOwner,
// _In_ int nFolder,
// _In_ HANDLE hToken,
// _In_ DWORD dwFlags,
// _Out_ LPTSTR pszPath
// );
source.getTarget().hasGlobalName(["SHGetFolderPath", "SHGetFolderPathA", "SHGetFolderPathW"]) and
use = source.getArgument(4)
or
// HRESULT SHGetFolderPathAndSubDir(
// _In_ HWND hwnd,
// _In_ int csidl,
// _In_ HANDLE hToken,
// _In_ DWORD dwFlags,
// _In_ LPCTSTR pszSubDir,
// _Out_ LPTSTR pszPath
// );
source
.getTarget()
.hasGlobalName([
"SHGetFolderPathAndSubDir", "SHGetFolderPathAndSubDirA", "SHGetFolderPathAndSubDirW"
]) and
use = source.getArgument(5)
}
/**
* Data obtained about Windows special paths (for example, the
* location of `System32`).
*/
class WindowsFolderPath extends SystemData {
WindowsFolderPath() { windowsFolderPath(this, _) }
override DataFlow::Node getAnExpr() { windowsFolderPath(this, result.asDefiningArgument()) }
}
private predicate logonUser(FunctionCall source, VariableAccess use) {
source.getTarget().hasGlobalName(["LogonUser", "LogonUserW", "LogonUserA"]) and
use = source.getAnArgument()
}
/**
* Data passed into a `LogonUser` (Windows) function.
*/
class LogonUser extends SystemData {
LogonUser() { logonUser(this, _) }
override DataFlow::Node getAnExpr() { logonUser(this, result.asConvertedExpr()) }
override predicate isSensitive() { any() }
}
/**
* The type of a registry query parameter, if it is of interest to us. This
* is used to express information about registry query parameters in the
* `regQuery` predicate concisely.
*/
private newtype TRegQueryParameter =
TSubKeyName() or
TValueName() or
TReturnData()
/**
* Registry query call (`source`) with information about parameters (`param`).
*/
private predicate regQuery(FunctionCall source, TRegQueryParameter paramType, Expr param) {
// LONG WINAPI RegQueryValue(
// _In_ HKEY hKey,
// _In_opt_ LPCTSTR lpSubKey,
// _Out_opt_ LPTSTR lpValue,
// _Inout_opt_ PLONG lpcbValue
// );
source.getTarget().hasGlobalName(["RegQueryValue", "RegQueryValueA", "RegQueryValueW"]) and
(
paramType = TSubKeyName() and param = source.getArgument(1)
or
paramType = TReturnData() and param = source.getArgument(2)
)
or
// LONG WINAPI RegQueryMultipleValues(
// _In_ HKEY hKey,
// _Out_ PVALENT val_list,
// _In_ DWORD num_vals,
// _Out_opt_ LPTSTR lpValueBuf,
// _Inout_opt_ LPDWORD ldwTotsize
// );
source
.getTarget()
.hasGlobalName([
"RegQueryMultipleValues", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW"
]) and
paramType = TReturnData() and
param = source.getArgument(3)
or
// LONG WINAPI RegQueryValueEx(
// _In_ HKEY hKey,
// _In_opt_ LPCTSTR lpValueName,
// _Reserved_ LPDWORD lpReserved,
// _Out_opt_ LPDWORD lpType,
// _Out_opt_ LPBYTE lpData,
// _Inout_opt_ LPDWORD lpcbData
// );
source.getTarget().hasGlobalName(["RegQueryValueEx", "RegQueryValueExA", "RegQueryValueExW"]) and
(
paramType = TValueName() and param = source.getArgument(1)
or
paramType = TReturnData() and param = source.getArgument(4)
)
or
// LONG WINAPI RegGetValue(
// _In_ HKEY hkey,
// _In_opt_ LPCTSTR lpSubKey,
// _In_opt_ LPCTSTR lpValue,
// _In_opt_ DWORD dwFlags,
// _Out_opt_ LPDWORD pdwType,
// _Out_opt_ PVOID pvData,
// _Inout_opt_ LPDWORD pcbData
// );
source.getTarget().hasGlobalName(["RegGetValue", "RegGetValueA", "RegGetValueW"]) and
(
paramType = TSubKeyName() and param = source.getArgument(1)
or
paramType = TValueName() and param = source.getArgument(2)
or
paramType = TReturnData() and param = source.getArgument(5)
)
}
/**
* Data read from the Windows registry.
*/
class RegQuery extends SystemData {
RegQuery() { regQuery(this, _, _) }
override DataFlow::Node getAnExpr() { regQuery(this, TReturnData(), result.asDefiningArgument()) }
override predicate isSensitive() {
exists(Expr e |
(
regQuery(this, TSubKeyName(), e) or
regQuery(this, TValueName(), e)
) and
e.getValue().toLowerCase().regexpMatch(".*(pass|token|key).*")
)
}
}

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* A new query, "Potential exposure of sensitive system data to an unauthorized control sphere" (`cpp/potential-system-data-exposure`) has been added. This query is focused on exposure of information that is highly likely to be sensitive, whereas the similar query "Exposure of system data to an unauthorized control sphere" (`cpp/system-data-exposure`) is focused on exposure of information on a channel that is more likely to be intercepted by an attacker.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `cpp/command-line-injection` query now takes into account calling contexts across string concatenations. This removes false positives due to mismatched calling contexts before and after string concatenations.

View File

@@ -3,4 +3,3 @@
- apply: code-scanning-selectors.yml
from: codeql/suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql/cpp-queries

View File

@@ -3,7 +3,6 @@
- apply: lgtm-selectors.yml
from: codeql/suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql/cpp-queries
# These are only for IDE use.
- exclude:
tags contain:

View File

@@ -3,4 +3,3 @@
- apply: security-and-quality-selectors.yml
from: codeql/suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql/cpp-queries

View File

@@ -3,4 +3,3 @@
- apply: security-extended-selectors.yml
from: codeql/suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql/cpp-queries

View File

@@ -0,0 +1,46 @@
/**
* @name Linux kernel double-fetch vulnerability detection
* @description Double-fetch is a very common vulnerability pattern
* in linux kernel, attacker can exploit double-fetch
* issues to obatain root privilege.
* Double-fetch is caused by fetching data from user
* mode by calling copy_from_user twice, CVE-2016-6480
* is quite a good example for your information.
* @kind problem
* @id cpp/linux-kernel-double-fetch-vulnerability
* @problem.severity warning
* @security-severity 7.5
* @tags security
* external/cwe/cwe-362
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
class CopyFromUserFunctionCall extends FunctionCall {
CopyFromUserFunctionCall() {
this.getTarget().getName() = "copy_from_user" and
not this.getArgument(1) instanceof AddressOfExpr
}
//root cause of double-fetech issue is read from
//the same user mode memory twice, so it makes
//sense that only check user mode pointer
predicate readFromSameUserModePointer(CopyFromUserFunctionCall another) {
globalValueNumber(this.getArgument(1)) = globalValueNumber(another.getArgument(1))
}
}
from CopyFromUserFunctionCall p1, CopyFromUserFunctionCall p2
where
not p1 = p2 and
p1.readFromSameUserModePointer(p2) and
exists(IfStmt ifStmt |
p1.getBasicBlock().getAFalseSuccessor*() = ifStmt.getBasicBlock() and
ifStmt.getBasicBlock().getAFalseSuccessor*() = p2.getBasicBlock()
) and
not exists(AssignPointerAddExpr assignPtrAdd |
globalValueNumber(p1.getArgument(1)) = globalValueNumber(assignPtrAdd.getLValue()) and
p1.getBasicBlock().getAFalseSuccessor*() = assignPtrAdd.getBasicBlock()
)
select p2, "Double fetch vulnerability. First fetch was $@.", p1, p1.toString()

View File

@@ -208,11 +208,16 @@ postWithInFlow
| lambdas.cpp:13:7:13:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:10:17:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:10:17:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:11:13:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:11:13:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:16:3:16:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:7:20:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:10:24:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:10:24:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:10:24:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:3 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:14 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -220,6 +225,8 @@ postWithInFlow
| lambdas.cpp:28:7:28:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:10:31:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:10:31:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:11:28:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:11:28:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:34:7:34:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:34:13:34:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:40:7:40:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -27,7 +27,8 @@
| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:29:2:29:15 | ... = ... | |
| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:33:7:33:9 | r_x | |
| arrayassignment.cpp:32:8:32:10 | p_x | arrayassignment.cpp:32:7:32:10 | * ... | TAINT |
| arrayassignment.cpp:37:7:37:7 | Unknown literal | arrayassignment.cpp:37:7:37:7 | constructor init of field i | TAINT |
| arrayassignment.cpp:37:7:37:7 | i | arrayassignment.cpp:37:7:37:7 | constructor init of field i | TAINT |
| arrayassignment.cpp:37:7:37:7 | i | arrayassignment.cpp:37:7:37:7 | i | |
| arrayassignment.cpp:37:7:37:7 | this | arrayassignment.cpp:37:7:37:7 | constructor init of field i [pre-this] | |
| arrayassignment.cpp:40:2:40:6 | this | arrayassignment.cpp:40:12:40:15 | constructor init of field i [pre-this] | |
| arrayassignment.cpp:40:12:40:15 | 0 | arrayassignment.cpp:40:12:40:15 | constructor init of field i | TAINT |
@@ -284,6 +285,7 @@
| copyableclass_declonly.cpp:67:13:67:18 | call to source | copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | TAINT |
| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:8:67:9 | ref arg s3 | TAINT |
| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:11:67:11 | call to operator= | TAINT |
| file://:0:0:0:0 | (unnamed parameter 0) | arrayassignment.cpp:37:7:37:7 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
@@ -299,6 +301,27 @@
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:75:8:75:8 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:75:8:75:8 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | structlikeclass.cpp:5:7:5:7 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | structlikeclass.cpp:5:7:5:7 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:228:11:228:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:228:11:228:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:235:11:235:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:235:11:235:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:235:11:235:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:243:11:243:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:243:11:243:11 | (unnamed parameter 0) | |
| format.cpp:16:21:16:21 | s | format.cpp:16:21:16:21 | s | |
| format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | |
| format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | |
@@ -3554,8 +3577,10 @@
| standalone_iterators.cpp:120:2:120:3 | it | standalone_iterators.cpp:120:5:120:5 | call to operator+= | TAINT |
| standalone_iterators.cpp:120:2:120:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | |
| standalone_iterators.cpp:120:8:120:13 | call to source | standalone_iterators.cpp:120:2:120:3 | ref arg it | TAINT |
| stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT |
| stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT |
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | constructor init of field container | TAINT |
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | constructor init of field container | TAINT |
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | container | |
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | container | |
| stl.h:75:8:75:8 | this | stl.h:75:8:75:8 | constructor init of field container [pre-this] | |
| stl.h:75:8:75:8 | this | stl.h:75:8:75:8 | constructor init of field container [pre-this] | |
| stl.h:95:69:95:69 | x | stl.h:95:69:95:69 | x | |
@@ -3573,16 +3598,6 @@
| stl.h:292:30:292:40 | call to allocator | stl.h:292:21:292:41 | noexcept(...) | TAINT |
| stl.h:292:30:292:40 | call to allocator | stl.h:292:21:292:41 | noexcept(...) | TAINT |
| stl.h:292:53:292:63 | 0 | stl.h:292:46:292:64 | (no string representation) | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | constructor init of field first [post-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | constructor init of field first [post-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | constructor init of field first [post-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
@@ -3593,6 +3608,26 @@
| stl.h:389:9:389:9 | constructor init of field first [pre-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | constructor init of field first [pre-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | constructor init of field first [pre-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | this | stl.h:389:9:389:9 | constructor init of field first [pre-this] | |
| stl.h:389:9:389:9 | this | stl.h:389:9:389:9 | constructor init of field first [pre-this] | |
| stl.h:389:9:389:9 | this | stl.h:389:9:389:9 | constructor init of field first [pre-this] | |
@@ -5354,10 +5389,12 @@
| stringstream.cpp:266:54:266:58 | ref arg call to flush | stringstream.cpp:266:35:266:39 | ref arg call to write | TAINT |
| stringstream.cpp:266:68:266:72 | xyz | stringstream.cpp:266:54:266:58 | ref arg call to flush | TAINT |
| stringstream.cpp:266:68:266:72 | xyz | stringstream.cpp:266:62:266:66 | call to write | TAINT |
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | v | |
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | v | |
| structlikeclass.cpp:8:2:8:16 | this | structlikeclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | |
| structlikeclass.cpp:8:22:8:23 | _v | structlikeclass.cpp:8:30:8:31 | _v | |
| structlikeclass.cpp:8:30:8:31 | _v | structlikeclass.cpp:8:28:8:32 | constructor init of field v | TAINT |
@@ -5973,24 +6010,29 @@
| taint.cpp:226:9:226:10 | 0 | taint.cpp:261:7:261:7 | w | |
| taint.cpp:228:10:232:2 | [...](...){...} | taint.cpp:233:7:233:7 | a | |
| taint.cpp:228:10:232:2 | {...} | taint.cpp:228:10:232:2 | [...](...){...} | |
| taint.cpp:228:11:228:11 | Unknown literal | taint.cpp:228:11:228:11 | constructor init of field t | TAINT |
| taint.cpp:228:11:228:11 | Unknown literal | taint.cpp:228:11:228:11 | constructor init of field u | TAINT |
| taint.cpp:228:11:228:11 | constructor init of field t [post-this] | taint.cpp:228:11:228:11 | constructor init of field u [pre-this] | |
| taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | taint.cpp:228:11:228:11 | constructor init of field u [pre-this] | |
| taint.cpp:228:11:228:11 | t | taint.cpp:228:11:228:11 | constructor init of field t | TAINT |
| taint.cpp:228:11:228:11 | t | taint.cpp:228:11:228:11 | t | |
| taint.cpp:228:11:228:11 | this | taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | |
| taint.cpp:228:11:228:11 | u | taint.cpp:228:11:228:11 | constructor init of field u | TAINT |
| taint.cpp:228:11:228:11 | u | taint.cpp:228:11:228:11 | u | |
| taint.cpp:228:17:228:17 | this | taint.cpp:229:3:229:6 | this | |
| taint.cpp:229:3:229:6 | this | taint.cpp:230:3:230:6 | this | |
| taint.cpp:230:3:230:6 | this | file://:0:0:0:0 | this | |
| taint.cpp:235:10:239:2 | [...](...){...} | taint.cpp:240:2:240:2 | b | |
| taint.cpp:235:10:239:2 | {...} | taint.cpp:235:10:239:2 | [...](...){...} | |
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field t | TAINT |
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field u | TAINT |
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field v | TAINT |
| taint.cpp:235:11:235:11 | constructor init of field t [post-this] | taint.cpp:235:11:235:11 | constructor init of field u [pre-this] | |
| taint.cpp:235:11:235:11 | constructor init of field t [pre-this] | taint.cpp:235:11:235:11 | constructor init of field u [pre-this] | |
| taint.cpp:235:11:235:11 | constructor init of field u [post-this] | taint.cpp:235:11:235:11 | constructor init of field v [pre-this] | |
| taint.cpp:235:11:235:11 | constructor init of field u [pre-this] | taint.cpp:235:11:235:11 | constructor init of field v [pre-this] | |
| taint.cpp:235:11:235:11 | t | taint.cpp:235:11:235:11 | constructor init of field t | TAINT |
| taint.cpp:235:11:235:11 | t | taint.cpp:235:11:235:11 | t | |
| taint.cpp:235:11:235:11 | this | taint.cpp:235:11:235:11 | constructor init of field t [pre-this] | |
| taint.cpp:235:11:235:11 | u | taint.cpp:235:11:235:11 | constructor init of field u | TAINT |
| taint.cpp:235:11:235:11 | u | taint.cpp:235:11:235:11 | u | |
| taint.cpp:235:11:235:11 | v | taint.cpp:235:11:235:11 | constructor init of field v | TAINT |
| taint.cpp:235:11:235:11 | v | taint.cpp:235:11:235:11 | v | |
| taint.cpp:235:15:235:15 | this | taint.cpp:236:3:236:6 | this | |
| taint.cpp:236:3:236:6 | this | taint.cpp:237:3:237:6 | this | |
| taint.cpp:237:3:237:6 | this | taint.cpp:238:3:238:14 | this | |
@@ -5998,11 +6040,13 @@
| taint.cpp:238:7:238:12 | call to source | taint.cpp:238:3:238:14 | ... = ... | |
| taint.cpp:243:10:246:2 | [...](...){...} | taint.cpp:247:2:247:2 | c | |
| taint.cpp:243:10:246:2 | {...} | taint.cpp:243:10:246:2 | [...](...){...} | |
| taint.cpp:243:11:243:11 | Unknown literal | taint.cpp:243:11:243:11 | constructor init of field t | TAINT |
| taint.cpp:243:11:243:11 | Unknown literal | taint.cpp:243:11:243:11 | constructor init of field u | TAINT |
| taint.cpp:243:11:243:11 | constructor init of field t [post-this] | taint.cpp:243:11:243:11 | constructor init of field u [pre-this] | |
| taint.cpp:243:11:243:11 | constructor init of field t [pre-this] | taint.cpp:243:11:243:11 | constructor init of field u [pre-this] | |
| taint.cpp:243:11:243:11 | t | taint.cpp:243:11:243:11 | constructor init of field t | TAINT |
| taint.cpp:243:11:243:11 | t | taint.cpp:243:11:243:11 | t | |
| taint.cpp:243:11:243:11 | this | taint.cpp:243:11:243:11 | constructor init of field t [pre-this] | |
| taint.cpp:243:11:243:11 | u | taint.cpp:243:11:243:11 | constructor init of field u | TAINT |
| taint.cpp:243:11:243:11 | u | taint.cpp:243:11:243:11 | u | |
| taint.cpp:243:15:243:15 | this | taint.cpp:244:3:244:6 | this | |
| taint.cpp:244:3:244:6 | this | taint.cpp:245:3:245:6 | this | |
| taint.cpp:249:11:252:2 | [...](...){...} | taint.cpp:253:2:253:2 | d | |

View File

@@ -12,8 +12,12 @@
| addressOf.cpp:40:15:40:15 | i | non-const address |
| addressOf.cpp:42:19:42:22 | iref | non-const address |
| addressOf.cpp:47:12:47:31 | captured | non-const address |
| addressOf.cpp:47:13:47:13 | (unnamed parameter 0) | |
| addressOf.cpp:47:13:47:13 | captured | |
| addressOf.cpp:47:19:47:28 | captured | |
| addressOf.cpp:48:3:48:4 | f1 | const address |
| addressOf.cpp:49:13:49:13 | (unnamed parameter 0) | |
| addressOf.cpp:49:13:49:13 | captured | |
| addressOf.cpp:49:15:49:22 | captured | non-const address |
| addressOf.cpp:49:27:49:36 | captured | |
| addressOf.cpp:50:3:50:4 | f2 | const address |
@@ -245,6 +249,10 @@
| test.cpp:173:19:173:19 | x | const address |
| test.cpp:174:20:174:20 | x | const address |
| test.cpp:175:7:175:7 | x | |
| test.cpp:178:8:178:8 | (unnamed parameter 0) | |
| test.cpp:178:8:178:8 | (unnamed parameter 0) | |
| test.cpp:178:8:178:8 | nested | |
| test.cpp:178:8:178:8 | x_ | |
| test.cpp:183:38:183:41 | yptr | |
| test.cpp:183:48:183:48 | z | |
| test.cpp:184:28:184:35 | static_y | non-const address |

View File

@@ -8,6 +8,10 @@
| addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref |
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:47:13:47:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:49:13:49:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip |
| indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |
| indirect_use.cpp:30:28:30:30 | ppp | indirect_use.cpp:31:19:31:21 | ppp |

View File

@@ -26,6 +26,10 @@
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:27:77:27 | x |
| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:47:13:47:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:49:13:49:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip |
| indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p |
| indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |

View File

@@ -12,6 +12,10 @@
| addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr |
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:47:13:47:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:49:13:49:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip |
| indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p |
| indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |

View File

@@ -155,15 +155,21 @@ bad_asts.cpp:
# 19| getInitializer(0): [ConstructorFieldInit] constructor init of field x
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| getExpr(): [Literal] Unknown literal
# 19| getExpr(): [FieldAccess] x
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| ValueCategory = prvalue(load)
# 19| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 19| Type = [LValueReferenceType] const Point &
# 19| ValueCategory = prvalue(load)
# 19| getInitializer(1): [ConstructorFieldInit] constructor init of field y
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| getExpr(): [Literal] Unknown literal
# 19| getExpr(): [FieldAccess] y
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| ValueCategory = prvalue(load)
# 19| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 19| Type = [LValueReferenceType] const Point &
# 19| ValueCategory = prvalue(load)
# 19| getEntryPoint(): [BlockStmt] { ... }
# 19| getStmt(0): [ReturnStmt] return ...
# 19| [MoveConstructor] void Bad::Point::Point(Bad::Point&&)
@@ -11645,51 +11651,75 @@ ir.cpp:
# 1486| getInitializer(0): [ConstructorFieldInit] constructor init of field i
# 1486| Type = [IntType] int
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] i
# 1486| Type = [IntType] int
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(1): [ConstructorFieldInit] constructor init of field d
# 1486| Type = [DoubleType] double
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] d
# 1486| Type = [DoubleType] double
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(2): [ConstructorFieldInit] constructor init of field b
# 1486| Type = [IntType] unsigned int
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] b
# 1486| Type = [IntType] unsigned int
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(3): [ConstructorFieldInit] constructor init of field r
# 1486| Type = [LValueReferenceType] int &
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] r
# 1486| Type = [LValueReferenceType] int &
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(4): [ConstructorFieldInit] constructor init of field p
# 1486| Type = [IntPointerType] int *
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] p
# 1486| Type = [IntPointerType] int *
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(5): [ConstructorFieldInit] constructor init of field xs
# 1486| Type = [CTypedefType,NestedTypedefType] ArrayType
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] xs
# 1486| Type = [CTypedefType,NestedTypedefType] ArrayType
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(6): [ConstructorFieldInit] constructor init of field r_alt
# 1486| Type = [CTypedefType,NestedTypedefType] RefType
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] r_alt
# 1486| Type = [CTypedefType,NestedTypedefType] RefType
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(7): [ConstructorFieldInit] constructor init of field m
# 1486| Type = [Struct] StructuredBindingDataMemberMemberStruct
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] m
# 1486| Type = [Struct] StructuredBindingDataMemberMemberStruct
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getEntryPoint(): [BlockStmt] { ... }
# 1486| getStmt(0): [ReturnStmt] return ...
# 1486| [MoveConstructor] void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct(StructuredBindingDataMemberStruct&&)
@@ -12066,21 +12096,30 @@ ir.cpp:
# 1539| getInitializer(0): [ConstructorFieldInit] constructor init of field i
# 1539| Type = [IntType] int
# 1539| ValueCategory = prvalue
# 1539| getExpr(): [Literal] Unknown literal
# 1539| getExpr(): [FieldAccess] i
# 1539| Type = [IntType] int
# 1539| ValueCategory = prvalue
# 1539| ValueCategory = prvalue(load)
# 1539| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1539| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
# 1539| ValueCategory = prvalue(load)
# 1539| getInitializer(1): [ConstructorFieldInit] constructor init of field d
# 1539| Type = [DoubleType] double
# 1539| ValueCategory = prvalue
# 1539| getExpr(): [Literal] Unknown literal
# 1539| getExpr(): [FieldAccess] d
# 1539| Type = [DoubleType] double
# 1539| ValueCategory = prvalue
# 1539| ValueCategory = prvalue(load)
# 1539| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1539| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
# 1539| ValueCategory = prvalue(load)
# 1539| getInitializer(2): [ConstructorFieldInit] constructor init of field r
# 1539| Type = [LValueReferenceType] int &
# 1539| ValueCategory = prvalue
# 1539| getExpr(): [Literal] Unknown literal
# 1539| getExpr(): [FieldAccess] r
# 1539| Type = [LValueReferenceType] int &
# 1539| ValueCategory = prvalue
# 1539| ValueCategory = prvalue(load)
# 1539| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1539| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
# 1539| ValueCategory = prvalue(load)
# 1539| getEntryPoint(): [BlockStmt] { ... }
# 1539| getStmt(0): [ReturnStmt] return ...
# 1539| [MoveConstructor] void StructuredBindingTupleRefGet::StructuredBindingTupleRefGet(StructuredBindingTupleRefGet&&)
@@ -13035,6 +13074,23 @@ ir.cpp:
# 1689| getEntryPoint(): [BlockStmt] { ... }
# 1689| getStmt(0): [EmptyStmt] ;
# 1689| getStmt(1): [ReturnStmt] return ...
# 1693| [TopLevelFunction] int goto_on_same_line()
# 1693| <params>:
# 1693| getEntryPoint(): [BlockStmt] { ... }
# 1694| getStmt(0): [DeclStmt] declaration
# 1694| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 1694| Type = [IntType] int
# 1694| getVariable().getInitializer(): [Initializer] initializer for x
# 1694| getExpr(): [Literal] 42
# 1694| Type = [IntType] int
# 1694| Value = [Literal] 42
# 1694| ValueCategory = prvalue
# 1695| getStmt(1): [GotoStmt] goto ...
# 1695| getStmt(2): [LabelStmt] label ...:
# 1696| getStmt(3): [ReturnStmt] return ...
# 1696| getExpr(): [VariableAccess] x
# 1696| Type = [IntType] int
# 1696| ValueCategory = prvalue(load)
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -1690,4 +1690,10 @@ void captured_lambda(int x, int &y, int &&z)
};
}
int goto_on_same_line() {
int x = 42;
goto next; next:
return x;
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -41,6 +41,35 @@
| bad_asts.cpp:16:7:16:23 | ChiTotal | total:m14_4 |
| bad_asts.cpp:16:7:16:23 | SideEffect | ~m14_4 |
| bad_asts.cpp:16:25:16:25 | Arg(0) | 0:r16_3 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_5 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_5 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_7 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_7 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_9 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_10 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_12 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_16 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_17 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_19 |
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_3 |
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_14 |
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_21 |
| bad_asts.cpp:19:10:19:10 | ChiTotal | total:m19_2 |
| bad_asts.cpp:19:10:19:10 | ChiTotal | total:m19_8 |
| bad_asts.cpp:19:10:19:10 | ChiTotal | total:m19_15 |
| bad_asts.cpp:19:10:19:10 | Load | m0_2 |
| bad_asts.cpp:19:10:19:10 | Load | m0_2 |
| bad_asts.cpp:19:10:19:10 | Load | m19_6 |
| bad_asts.cpp:19:10:19:10 | Load | ~m0_4 |
| bad_asts.cpp:19:10:19:10 | Load | ~m0_4 |
| bad_asts.cpp:19:10:19:10 | SideEffect | m19_3 |
| bad_asts.cpp:19:10:19:10 | SideEffect | m19_22 |
| bad_asts.cpp:19:10:19:10 | StoreValue | r19_13 |
| bad_asts.cpp:19:10:19:10 | StoreValue | r19_20 |
| bad_asts.cpp:19:10:19:10 | Unary | m19_6 |
| bad_asts.cpp:19:10:19:10 | Unary | m19_6 |
| bad_asts.cpp:19:10:19:10 | Unary | r19_11 |
| bad_asts.cpp:19:10:19:10 | Unary | r19_18 |
| bad_asts.cpp:22:5:22:9 | Address | &:r22_5 |
| bad_asts.cpp:22:5:22:9 | Address | &:r22_5 |
| bad_asts.cpp:22:5:22:9 | Address | &:r22_7 |
@@ -633,6 +662,12 @@
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_2 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
@@ -643,6 +678,12 @@
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_5 |
@@ -692,6 +733,9 @@
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m745_6 |
| file://:0:0:0:0 | Load | m754_6 |
| file://:0:0:0:0 | Load | m763_6 |
@@ -706,6 +750,9 @@
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m1078_23 |
| file://:0:0:0:0 | SideEffect | m1078_23 |
| file://:0:0:0:0 | SideEffect | m1084_23 |
@@ -6769,13 +6816,102 @@
| ir.cpp:1482:8:1482:8 | SideEffect | m1482_8 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_9 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_10 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_12 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_16 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_17 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_19 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_23 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_24 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_26 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_30 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_31 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_33 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_37 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_38 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_40 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_44 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_45 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_47 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_51 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_52 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_54 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_58 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_59 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_61 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_3 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_3 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_14 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_21 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_28 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_35 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_42 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_49 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_56 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_63 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_2 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_2 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_8 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_15 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_22 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_29 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_36 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_43 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_50 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_57 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m1486_6 |
| ir.cpp:1486:8:1486:8 | Load | m1486_6 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_3 |
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_3 |
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_8 |
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_64 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_13 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_20 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_27 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_34 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_41 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_48 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_55 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_62 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_11 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_18 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_25 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_32 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_39 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_46 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_53 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_60 |
| ir.cpp:1499:6:1499:35 | ChiPartial | partial:m1499_3 |
| ir.cpp:1499:6:1499:35 | ChiTotal | total:m1499_2 |
| ir.cpp:1499:6:1499:35 | SideEffect | ~m1525_7 |
@@ -6948,13 +7084,52 @@
| ir.cpp:1528:17:1528:17 | StoreValue | r1528_4 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_9 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_10 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_12 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_16 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_17 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_19 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_23 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_24 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_26 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_3 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_3 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_14 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_21 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_28 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_2 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_2 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_8 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_15 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_22 |
| ir.cpp:1539:8:1539:8 | Load | m0_2 |
| ir.cpp:1539:8:1539:8 | Load | m0_2 |
| ir.cpp:1539:8:1539:8 | Load | m0_2 |
| ir.cpp:1539:8:1539:8 | Load | m1539_6 |
| ir.cpp:1539:8:1539:8 | Load | m1539_6 |
| ir.cpp:1539:8:1539:8 | Load | ~m0_4 |
| ir.cpp:1539:8:1539:8 | Load | ~m0_4 |
| ir.cpp:1539:8:1539:8 | Load | ~m0_4 |
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_3 |
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_3 |
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_8 |
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_29 |
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_13 |
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_20 |
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_27 |
| ir.cpp:1539:8:1539:8 | Unary | m1539_6 |
| ir.cpp:1539:8:1539:8 | Unary | m1539_6 |
| ir.cpp:1539:8:1539:8 | Unary | m1539_6 |
| ir.cpp:1539:8:1539:8 | Unary | r1539_11 |
| ir.cpp:1539:8:1539:8 | Unary | r1539_18 |
| ir.cpp:1539:8:1539:8 | Unary | r1539_25 |
| ir.cpp:1567:60:1567:95 | Address | &:r1567_5 |
| ir.cpp:1567:60:1567:95 | Address | &:r1567_5 |
| ir.cpp:1567:60:1567:95 | Address | &:r1567_7 |
@@ -7527,6 +7702,17 @@
| ir.cpp:1689:50:1689:50 | Load | m1689_6 |
| ir.cpp:1689:50:1689:50 | SideEffect | m1689_3 |
| ir.cpp:1689:50:1689:50 | SideEffect | m1689_8 |
| ir.cpp:1693:5:1693:21 | Address | &:r1693_5 |
| ir.cpp:1693:5:1693:21 | ChiPartial | partial:m1693_3 |
| ir.cpp:1693:5:1693:21 | ChiTotal | total:m1693_2 |
| ir.cpp:1693:5:1693:21 | Load | m1696_4 |
| ir.cpp:1693:5:1693:21 | SideEffect | m1693_3 |
| ir.cpp:1694:7:1694:7 | Address | &:r1694_1 |
| ir.cpp:1694:10:1694:12 | StoreValue | r1694_2 |
| ir.cpp:1696:3:1696:11 | Address | &:r1696_1 |
| ir.cpp:1696:10:1696:10 | Address | &:r1696_2 |
| ir.cpp:1696:10:1696:10 | Load | m1694_3 |
| ir.cpp:1696:10:1696:10 | StoreValue | r1696_3 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |

View File

@@ -49,6 +49,38 @@ bad_asts.cpp:
# 14| v14_5(void) = AliasedUse : ~m?
# 14| v14_6(void) = ExitFunction :
# 19| void Bad::Point::Point(Bad::Point const&)
# 19| Block 0
# 19| v19_1(void) = EnterFunction :
# 19| mu19_2(unknown) = AliasedDefinition :
# 19| mu19_3(unknown) = InitializeNonLocal :
# 19| r19_4(glval<unknown>) = VariableAddress[#this] :
# 19| mu19_5(glval<Point>) = InitializeParameter[#this] : &:r19_4
# 19| r19_6(glval<Point>) = Load[#this] : &:r19_4, ~m?
# 19| mu19_7(Point) = InitializeIndirection[#this] : &:r19_6
#-----| r0_1(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
#-----| mu0_2(Point &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
#-----| r0_3(Point &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
# 19| r19_8(glval<int>) = FieldAddress[x] : mu19_5
# 19| r19_9(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
# 19| r19_10(Point &) = Load[(unnamed parameter 0)] : &:r19_9, ~m?
# 19| r19_11(glval<int>) = FieldAddress[x] : r19_10
# 19| r19_12(int) = Load[?] : &:r19_11, ~m?
# 19| mu19_13(int) = Store[?] : &:r19_8, r19_12
# 19| r19_14(glval<int>) = FieldAddress[y] : mu19_5
# 19| r19_15(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
# 19| r19_16(Point &) = Load[(unnamed parameter 0)] : &:r19_15, ~m?
# 19| r19_17(glval<int>) = FieldAddress[y] : r19_16
# 19| r19_18(int) = Load[?] : &:r19_17, ~m?
# 19| mu19_19(int) = Store[?] : &:r19_14, r19_18
# 19| v19_20(void) = NoOp :
# 19| v19_21(void) = ReturnIndirection[#this] : &:r19_6, ~m?
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
# 19| v19_22(void) = ReturnVoid :
# 19| v19_23(void) = AliasedUse : ~m?
# 19| v19_24(void) = ExitFunction :
# 22| void Bad::Point::Point()
# 22| Block 0
# 22| v22_1(void) = EnterFunction :
@@ -8029,6 +8061,74 @@ ir.cpp:
# 1486| v1486_16(void) = AliasedUse : ~m?
# 1486| v1486_17(void) = ExitFunction :
# 1486| void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct(StructuredBindingDataMemberStruct const&)
# 1486| Block 0
# 1486| v1486_1(void) = EnterFunction :
# 1486| mu1486_2(unknown) = AliasedDefinition :
# 1486| mu1486_3(unknown) = InitializeNonLocal :
# 1486| r1486_4(glval<unknown>) = VariableAddress[#this] :
# 1486| mu1486_5(glval<StructuredBindingDataMemberStruct>) = InitializeParameter[#this] : &:r1486_4
# 1486| r1486_6(glval<StructuredBindingDataMemberStruct>) = Load[#this] : &:r1486_4, ~m?
# 1486| mu1486_7(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1486_6
#-----| r0_1(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
#-----| mu0_2(StructuredBindingDataMemberStruct &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
#-----| r0_3(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
# 1486| r1486_8(glval<int>) = FieldAddress[i] : mu1486_5
# 1486| r1486_9(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_10(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_9, ~m?
# 1486| r1486_11(glval<int>) = FieldAddress[i] : r1486_10
# 1486| r1486_12(int) = Load[?] : &:r1486_11, ~m?
# 1486| mu1486_13(int) = Store[?] : &:r1486_8, r1486_12
# 1486| r1486_14(glval<double>) = FieldAddress[d] : mu1486_5
# 1486| r1486_15(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_16(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_15, ~m?
# 1486| r1486_17(glval<double>) = FieldAddress[d] : r1486_16
# 1486| r1486_18(double) = Load[?] : &:r1486_17, ~m?
# 1486| mu1486_19(double) = Store[?] : &:r1486_14, r1486_18
# 1486| r1486_20(glval<unsigned int>) = FieldAddress[b] : mu1486_5
# 1486| r1486_21(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_22(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_21, ~m?
# 1486| r1486_23(glval<unsigned int>) = FieldAddress[b] : r1486_22
# 1486| r1486_24(unsigned int) = Load[?] : &:r1486_23, ~m?
# 1486| mu1486_25(unsigned int) = Store[?] : &:r1486_20, r1486_24
# 1486| r1486_26(glval<int &>) = FieldAddress[r] : mu1486_5
# 1486| r1486_27(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_28(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_27, ~m?
# 1486| r1486_29(glval<int &>) = FieldAddress[r] : r1486_28
# 1486| r1486_30(int &) = Load[?] : &:r1486_29, ~m?
# 1486| mu1486_31(int &) = Store[?] : &:r1486_26, r1486_30
# 1486| r1486_32(glval<int *>) = FieldAddress[p] : mu1486_5
# 1486| r1486_33(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_34(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_33, ~m?
# 1486| r1486_35(glval<int *>) = FieldAddress[p] : r1486_34
# 1486| r1486_36(int *) = Load[?] : &:r1486_35, ~m?
# 1486| mu1486_37(int *) = Store[?] : &:r1486_32, r1486_36
# 1486| r1486_38(glval<int[2]>) = FieldAddress[xs] : mu1486_5
# 1486| r1486_39(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_40(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_39, ~m?
# 1486| r1486_41(glval<int[2]>) = FieldAddress[xs] : r1486_40
# 1486| r1486_42(int[2]) = Load[?] : &:r1486_41, ~m?
# 1486| mu1486_43(int[2]) = Store[?] : &:r1486_38, r1486_42
# 1486| r1486_44(glval<int &>) = FieldAddress[r_alt] : mu1486_5
# 1486| r1486_45(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_46(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_45, ~m?
# 1486| r1486_47(glval<int &>) = FieldAddress[r_alt] : r1486_46
# 1486| r1486_48(int &) = Load[?] : &:r1486_47, ~m?
# 1486| mu1486_49(int &) = Store[?] : &:r1486_44, r1486_48
# 1486| r1486_50(glval<StructuredBindingDataMemberMemberStruct>) = FieldAddress[m] : mu1486_5
# 1486| r1486_51(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_52(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_51, ~m?
# 1486| r1486_53(glval<StructuredBindingDataMemberMemberStruct>) = FieldAddress[m] : r1486_52
# 1486| r1486_54(StructuredBindingDataMemberMemberStruct) = Load[?] : &:r1486_53, ~m?
# 1486| mu1486_55(StructuredBindingDataMemberMemberStruct) = Store[?] : &:r1486_50, r1486_54
# 1486| v1486_56(void) = NoOp :
# 1486| v1486_57(void) = ReturnIndirection[#this] : &:r1486_6, ~m?
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
# 1486| v1486_58(void) = ReturnVoid :
# 1486| v1486_59(void) = AliasedUse : ~m?
# 1486| v1486_60(void) = ExitFunction :
# 1499| void data_member_structured_binding()
# 1499| Block 0
# 1499| v1499_1(void) = EnterFunction :
@@ -8209,6 +8309,44 @@ ir.cpp:
# 1539| v1539_11(void) = AliasedUse : ~m?
# 1539| v1539_12(void) = ExitFunction :
# 1539| void StructuredBindingTupleRefGet::StructuredBindingTupleRefGet(StructuredBindingTupleRefGet const&)
# 1539| Block 0
# 1539| v1539_1(void) = EnterFunction :
# 1539| mu1539_2(unknown) = AliasedDefinition :
# 1539| mu1539_3(unknown) = InitializeNonLocal :
# 1539| r1539_4(glval<unknown>) = VariableAddress[#this] :
# 1539| mu1539_5(glval<StructuredBindingTupleRefGet>) = InitializeParameter[#this] : &:r1539_4
# 1539| r1539_6(glval<StructuredBindingTupleRefGet>) = Load[#this] : &:r1539_4, ~m?
# 1539| mu1539_7(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1539_6
#-----| r0_1(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
#-----| mu0_2(StructuredBindingTupleRefGet &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
#-----| r0_3(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
# 1539| r1539_8(glval<int>) = FieldAddress[i] : mu1539_5
# 1539| r1539_9(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
# 1539| r1539_10(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_9, ~m?
# 1539| r1539_11(glval<int>) = FieldAddress[i] : r1539_10
# 1539| r1539_12(int) = Load[?] : &:r1539_11, ~m?
# 1539| mu1539_13(int) = Store[?] : &:r1539_8, r1539_12
# 1539| r1539_14(glval<double>) = FieldAddress[d] : mu1539_5
# 1539| r1539_15(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
# 1539| r1539_16(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_15, ~m?
# 1539| r1539_17(glval<double>) = FieldAddress[d] : r1539_16
# 1539| r1539_18(double) = Load[?] : &:r1539_17, ~m?
# 1539| mu1539_19(double) = Store[?] : &:r1539_14, r1539_18
# 1539| r1539_20(glval<int &>) = FieldAddress[r] : mu1539_5
# 1539| r1539_21(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
# 1539| r1539_22(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_21, ~m?
# 1539| r1539_23(glval<int &>) = FieldAddress[r] : r1539_22
# 1539| r1539_24(int &) = Load[?] : &:r1539_23, ~m?
# 1539| mu1539_25(int &) = Store[?] : &:r1539_20, r1539_24
# 1539| v1539_26(void) = NoOp :
# 1539| v1539_27(void) = ReturnIndirection[#this] : &:r1539_6, ~m?
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
# 1539| v1539_28(void) = ReturnVoid :
# 1539| v1539_29(void) = AliasedUse : ~m?
# 1539| v1539_30(void) = ExitFunction :
# 1567| std::tuple_element<int 0, StructuredBindingTupleRefGet>::type& StructuredBindingTupleRefGet::get<int 0>()
# 1567| Block 0
# 1567| v1567_1(void) = EnterFunction :
@@ -8842,6 +8980,25 @@ ir.cpp:
# 1689| v1689_12(void) = AliasedUse : ~m?
# 1689| v1689_13(void) = ExitFunction :
# 1693| int goto_on_same_line()
# 1693| Block 0
# 1693| v1693_1(void) = EnterFunction :
# 1693| mu1693_2(unknown) = AliasedDefinition :
# 1693| mu1693_3(unknown) = InitializeNonLocal :
# 1694| r1694_1(glval<int>) = VariableAddress[x] :
# 1694| r1694_2(int) = Constant[42] :
# 1694| mu1694_3(int) = Store[x] : &:r1694_1, r1694_2
# 1695| v1695_1(void) = NoOp :
# 1695| v1695_2(void) = NoOp :
# 1696| r1696_1(glval<int>) = VariableAddress[#return] :
# 1696| r1696_2(glval<int>) = VariableAddress[x] :
# 1696| r1696_3(int) = Load[x] : &:r1696_2, ~m?
# 1696| mu1696_4(int) = Store[#return] : &:r1696_1, r1696_3
# 1693| r1693_4(glval<int>) = VariableAddress[#return] :
# 1693| v1693_5(void) = ReturnValue : &:r1693_4, ~m?
# 1693| v1693_6(void) = AliasedUse : ~m?
# 1693| v1693_7(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -125,8 +125,8 @@
| captures.cpp:22:19:22:19 | (unnamed constructor) |
| captures.cpp:22:19:22:19 | (unnamed constructor) |
| captures.cpp:22:19:22:19 | (unnamed constructor) |
| captures.cpp:22:19:22:19 | Unknown literal |
| captures.cpp:22:19:22:19 | Unknown literal |
| captures.cpp:22:19:22:19 | (unnamed parameter 0) |
| captures.cpp:22:19:22:19 | (unnamed parameter 0) |
| captures.cpp:22:19:22:19 | constructor init of field x |
| captures.cpp:22:19:22:19 | constructor init of field y |
| captures.cpp:22:19:22:19 | declaration of (unnamed constructor) |
@@ -135,6 +135,8 @@
| captures.cpp:22:19:22:19 | definition of operator= |
| captures.cpp:22:19:22:19 | operator= |
| captures.cpp:22:19:22:19 | return ... |
| captures.cpp:22:19:22:19 | x |
| captures.cpp:22:19:22:19 | y |
| captures.cpp:22:19:22:19 | { ... } |
| captures.cpp:22:23:22:23 | definition of x |
| captures.cpp:22:23:22:23 | x |
@@ -185,12 +187,13 @@
| end_pos.cpp:9:15:9:15 | (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | Unknown literal |
| end_pos.cpp:9:15:9:15 | (unnamed parameter 0) |
| end_pos.cpp:9:15:9:15 | constructor init of field ii |
| end_pos.cpp:9:15:9:15 | declaration of (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | definition of (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | definition of (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | definition of operator= |
| end_pos.cpp:9:15:9:15 | ii |
| end_pos.cpp:9:15:9:15 | operator= |
| end_pos.cpp:9:15:9:15 | return ... |
| end_pos.cpp:9:15:9:15 | { ... } |

View File

@@ -1498,6 +1498,8 @@ postWithInFlow
| bad_asts.cpp:15:10:15:12 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:16:5:16:5 | s [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:16:5:16:5 | s [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:19:10:19:10 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:19:10:19:10 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:27:11:27:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| break_labels.c:3:9:3:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| break_labels.c:5:9:5:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -1626,11 +1628,15 @@ postWithInFlow
| cpp11.cpp:60:15:60:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:65:10:65:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:65:19:65:45 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:65:20:65:20 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:65:35:65:43 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:77:19:77:21 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:77:19:77:21 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:11:82:14 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:11:82:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:17 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:17 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:17 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:55 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:55 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:55 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -3,7 +3,6 @@ edges
| tests.cpp:33:34:33:39 | call to getenv | tests.cpp:38:39:38:49 | environment indirection |
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:26:15:26:23 | ReturnValue |
| tests.cpp:38:39:38:49 | environment indirection | tests.cpp:38:25:38:36 | strncat output argument |
| tests.cpp:38:39:38:49 | environment indirection | tests.cpp:38:25:38:36 | strncat output argument |
| tests.cpp:51:12:51:20 | call to badSource | tests.cpp:53:16:53:19 | data indirection |
nodes
| tests.cpp:26:15:26:23 | ReturnValue | semmle.label | ReturnValue |

View File

@@ -2,64 +2,55 @@ edges
| test.cpp:16:20:16:23 | argv | test.cpp:22:45:22:52 | userName indirection |
| test.cpp:22:13:22:20 | sprintf output argument | test.cpp:23:12:23:19 | command1 indirection |
| test.cpp:22:45:22:52 | userName indirection | test.cpp:22:13:22:20 | sprintf output argument |
| test.cpp:22:45:22:52 | userName indirection | test.cpp:22:13:22:20 | sprintf output argument |
| test.cpp:47:21:47:26 | call to getenv | test.cpp:50:35:50:43 | envCflags indirection |
| test.cpp:50:11:50:17 | sprintf output argument | test.cpp:51:10:51:16 | command indirection |
| test.cpp:50:35:50:43 | envCflags indirection | test.cpp:50:11:50:17 | sprintf output argument |
| test.cpp:50:35:50:43 | envCflags indirection | test.cpp:50:11:50:17 | sprintf output argument |
| test.cpp:62:9:62:16 | fread output argument | test.cpp:64:20:64:27 | filename indirection |
| test.cpp:64:11:64:17 | strncat output argument | test.cpp:65:10:65:16 | command indirection |
| test.cpp:64:20:64:27 | filename indirection | test.cpp:64:11:64:17 | strncat output argument |
| test.cpp:64:20:64:27 | filename indirection | test.cpp:64:11:64:17 | strncat output argument |
| test.cpp:82:9:82:16 | fread output argument | test.cpp:84:20:84:27 | filename indirection |
| test.cpp:84:11:84:17 | strncat output argument | test.cpp:85:32:85:38 | command indirection |
| test.cpp:84:20:84:27 | filename indirection | test.cpp:84:11:84:17 | strncat output argument |
| test.cpp:84:20:84:27 | filename indirection | test.cpp:84:11:84:17 | strncat output argument |
| test.cpp:91:9:91:16 | fread output argument | test.cpp:93:17:93:24 | filename indirection |
| test.cpp:93:11:93:14 | strncat output argument | test.cpp:94:45:94:48 | path indirection |
| test.cpp:93:17:93:24 | filename indirection | test.cpp:93:11:93:14 | strncat output argument |
| test.cpp:93:17:93:24 | filename indirection | test.cpp:93:11:93:14 | strncat output argument |
| test.cpp:106:20:106:25 | call to getenv | test.cpp:107:33:107:36 | path indirection |
| test.cpp:107:31:107:31 | call to operator+ | test.cpp:108:18:108:22 | call to c_str indirection |
| test.cpp:107:33:107:36 | path indirection | test.cpp:107:31:107:31 | call to operator+ |
| test.cpp:107:33:107:36 | path indirection | test.cpp:107:31:107:31 | call to operator+ |
| test.cpp:113:20:113:25 | call to getenv | test.cpp:114:19:114:22 | path indirection |
| test.cpp:114:17:114:17 | Call | test.cpp:114:25:114:29 | call to c_str indirection |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | Call |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | Call |
| test.cpp:119:20:119:25 | call to getenv | test.cpp:120:19:120:22 | path indirection |
| test.cpp:120:17:120:17 | Call | test.cpp:120:10:120:30 | call to data indirection |
| test.cpp:120:19:120:22 | path indirection | test.cpp:120:17:120:17 | Call |
| test.cpp:120:19:120:22 | path indirection | test.cpp:120:17:120:17 | Call |
| test.cpp:140:9:140:11 | fread output argument | test.cpp:142:31:142:33 | str indirection |
| test.cpp:142:11:142:17 | sprintf output argument | test.cpp:143:10:143:16 | command indirection |
| test.cpp:142:31:142:33 | str indirection | test.cpp:142:11:142:17 | sprintf output argument |
| test.cpp:142:31:142:33 | str indirection | test.cpp:142:11:142:17 | sprintf output argument |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:177:20:177:27 | filename indirection |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:178:22:178:26 | flags indirection |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:180:22:180:29 | filename indirection |
| test.cpp:177:13:177:17 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:177:20:177:27 | filename indirection | test.cpp:177:13:177:17 | strncat output argument |
| test.cpp:177:20:177:27 | filename indirection | test.cpp:177:13:177:17 | strncat output argument |
| test.cpp:178:13:178:19 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:178:22:178:26 | flags indirection | test.cpp:178:13:178:19 | strncat output argument |
| test.cpp:178:22:178:26 | flags indirection | test.cpp:178:13:178:19 | strncat output argument |
| test.cpp:180:13:180:19 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:180:22:180:29 | filename indirection | test.cpp:180:13:180:19 | strncat output argument |
| test.cpp:180:22:180:29 | filename indirection | test.cpp:180:13:180:19 | strncat output argument |
| test.cpp:186:47:186:54 | *filename | test.cpp:187:18:187:25 | filename indirection |
| test.cpp:186:47:186:54 | *filename | test.cpp:188:20:188:24 | flags indirection |
| test.cpp:186:47:186:54 | filename | test.cpp:187:18:187:25 | filename indirection |
| test.cpp:186:47:186:54 | filename | test.cpp:188:20:188:24 | flags indirection |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:18:187:25 | filename indirection | test.cpp:187:11:187:15 | strncat output argument |
| test.cpp:187:18:187:25 | filename indirection | test.cpp:187:11:187:15 | strncat output argument |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:205:10:205:16 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:205:10:205:16 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:20:188:24 | flags indirection | test.cpp:188:11:188:17 | strncat output argument |
@@ -67,9 +58,21 @@ edges
| test.cpp:194:9:194:16 | fread output argument | test.cpp:196:26:196:33 | filename |
| test.cpp:194:9:194:16 | fread output argument | test.cpp:196:26:196:33 | filename indirection |
| test.cpp:196:10:196:16 | command [post update] | test.cpp:198:32:198:38 | command indirection |
| test.cpp:196:10:196:16 | command [post update] | test.cpp:198:32:198:38 | command indirection |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename |
| test.cpp:196:26:196:33 | filename | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename |
| test.cpp:205:10:205:16 | command [post update] | test.cpp:207:32:207:38 | command indirection |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:218:9:218:16 | fread output argument | test.cpp:220:19:220:26 | filename indirection |
| test.cpp:218:9:218:16 | fread output argument | test.cpp:220:19:220:26 | filename indirection |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
nodes
| test.cpp:16:20:16:23 | argv | semmle.label | argv |
| test.cpp:22:13:22:20 | sprintf output argument | semmle.label | sprintf output argument |
@@ -115,22 +118,48 @@ nodes
| test.cpp:180:13:180:19 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:180:22:180:29 | filename indirection | semmle.label | filename indirection |
| test.cpp:183:32:183:38 | command indirection | semmle.label | command indirection |
| test.cpp:183:32:183:38 | command indirection | semmle.label | command indirection |
| test.cpp:183:32:183:38 | command indirection | semmle.label | command indirection |
| test.cpp:186:47:186:54 | *filename | semmle.label | *filename |
| test.cpp:186:47:186:54 | filename | semmle.label | filename |
| test.cpp:187:11:187:15 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:187:11:187:15 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:187:18:187:25 | filename indirection | semmle.label | filename indirection |
| test.cpp:187:18:187:25 | filename indirection | semmle.label | filename indirection |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:188:11:188:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:188:20:188:24 | flags indirection | semmle.label | flags indirection |
| test.cpp:188:20:188:24 | flags indirection | semmle.label | flags indirection |
| test.cpp:194:9:194:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:196:10:196:16 | command [post update] | semmle.label | command [post update] |
| test.cpp:196:10:196:16 | command [post update] | semmle.label | command [post update] |
| test.cpp:196:26:196:33 | filename | semmle.label | filename |
| test.cpp:196:26:196:33 | filename indirection | semmle.label | filename indirection |
| test.cpp:198:32:198:38 | command indirection | semmle.label | command indirection |
| test.cpp:205:10:205:16 | command [post update] | semmle.label | command [post update] |
| test.cpp:207:32:207:38 | command indirection | semmle.label | command indirection |
| test.cpp:198:32:198:38 | command indirection | semmle.label | command indirection |
| test.cpp:218:9:218:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:220:10:220:16 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:220:10:220:16 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
| test.cpp:222:32:222:38 | command indirection | semmle.label | command indirection |
subpaths
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
#select
| test.cpp:23:12:23:19 | command1 | test.cpp:16:20:16:23 | argv | test.cpp:23:12:23:19 | command1 indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:16:20:16:23 | argv | user input (a command-line argument) | test.cpp:22:13:22:20 | sprintf output argument | sprintf output argument |
| test.cpp:51:10:51:16 | command | test.cpp:47:21:47:26 | call to getenv | test.cpp:51:10:51:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:47:21:47:26 | call to getenv | user input (an environment variable) | test.cpp:50:11:50:17 | sprintf output argument | sprintf output argument |
@@ -146,5 +175,5 @@ subpaths
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:180:13:180:19 | strncat output argument | strncat output argument |
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:187:11:187:15 | strncat output argument | strncat output argument |
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:188:11:188:17 | strncat output argument | strncat output argument |
| test.cpp:207:32:207:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:207:32:207:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:187:11:187:15 | strncat output argument | strncat output argument |
| test.cpp:207:32:207:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:207:32:207:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:188:11:188:17 | strncat output argument | strncat output argument |
| test.cpp:222:32:222:38 | command | test.cpp:218:9:218:16 | fread output argument | test.cpp:222:32:222:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:218:9:218:16 | fread output argument | user input (String read by fread) | test.cpp:220:10:220:16 | strncat output argument | strncat output argument |
| test.cpp:222:32:222:38 | command | test.cpp:218:9:218:16 | fread output argument | test.cpp:222:32:222:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:218:9:218:16 | fread output argument | user input (String read by fread) | test.cpp:220:10:220:16 | strncat output argument | strncat output argument |

View File

@@ -199,7 +199,7 @@ void test17(FILE *f) {
}
void test18() {
// GOOD [FALSE POSITIVE]
// GOOD
char command[1000] = "ls ", flags[1000] = "-l", filename[1000] = ".";
concat(command, flags, filename);
@@ -207,4 +207,19 @@ void test18() {
execl("/bin/sh", "sh", "-c", command);
}
#define CONCAT(COMMAND, FILENAME) \
strncat(COMMAND, FILENAME, 1000); \
strncat(COMMAND, " ", 1000); \
strncat(COMMAND, FILENAME, 1000);
void test19(FILE *f) {
// BAD: the user string is injected directly into a command
char command[1000] = "mv ", filename[1000];
fread(filename, 1, 1000, f);
CONCAT(command, filename)
execl("/bin/sh", "sh", "-c", command);
}
// open question: do we want to report certain sources even when they're the start of the string?

View File

@@ -0,0 +1,8 @@
edges
| tests.c:57:21:57:28 | password | tests.c:70:70:70:77 | array to pointer conversion |
nodes
| tests.c:57:21:57:28 | password | semmle.label | password |
| tests.c:70:70:70:77 | array to pointer conversion | semmle.label | array to pointer conversion |
subpaths
#select
| tests.c:70:70:70:77 | array to pointer conversion | tests.c:57:21:57:28 | password | tests.c:70:70:70:77 | array to pointer conversion | This operation potentially exposes sensitive system data from $@. | tests.c:57:21:57:28 | password | password |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-497/PotentiallyExposedSystemData.ql

View File

@@ -67,6 +67,6 @@ void CWE535_Info_Exposure_Shell_Error__w32_char_01_bad()
printLine("Unable to login.");
}
/* FLAW: Write sensitive data to stderr */
fprintf(stderr, "User attempted access with password: %s\n", password); // [NOT DETECTED]
fprintf(stderr, "User attempted access with password: %s\n", password);
}
}

View File

@@ -2,15 +2,26 @@ edges
| tests2.cpp:63:13:63:18 | call to getenv | tests2.cpp:63:13:63:26 | (const char *)... |
| tests2.cpp:64:13:64:18 | call to getenv | tests2.cpp:64:13:64:26 | (const char *)... |
| tests2.cpp:65:13:65:18 | call to getenv | tests2.cpp:65:13:65:30 | (const char *)... |
| tests2.cpp:76:18:76:38 | call to mysql_get_client_info | tests2.cpp:79:14:79:19 | (const char *)... |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info |
| tests2.cpp:89:42:89:45 | str1 | tests2.cpp:91:14:91:17 | str1 |
| tests2.cpp:99:8:99:15 | call to getpwuid | tests2.cpp:100:14:100:15 | pw |
| tests2.cpp:107:3:107:4 | c1 [post update] [ptr] | tests2.cpp:109:14:109:15 | c1 [read] [ptr] |
| tests2.cpp:107:6:107:8 | ptr [post update] | tests2.cpp:107:3:107:4 | c1 [post update] [ptr] |
| tests2.cpp:107:12:107:17 | call to getenv | tests2.cpp:107:6:107:8 | ptr [post update] |
| tests2.cpp:109:14:109:15 | c1 [read] [ptr] | tests2.cpp:109:14:109:19 | (const char *)... |
| tests2.cpp:66:13:66:18 | call to getenv | tests2.cpp:66:13:66:34 | (const char *)... |
| tests2.cpp:78:18:78:38 | call to mysql_get_client_info | tests2.cpp:81:14:81:19 | (const char *)... |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info |
| tests2.cpp:91:42:91:45 | str1 | tests2.cpp:93:14:93:17 | str1 |
| tests2.cpp:101:8:101:15 | call to getpwuid | tests2.cpp:102:14:102:15 | pw |
| tests2.cpp:109:3:109:4 | c1 [post update] [ptr] | tests2.cpp:111:14:111:15 | c1 [read] [ptr] |
| tests2.cpp:109:6:109:8 | ptr [post update] | tests2.cpp:109:3:109:4 | c1 [post update] [ptr] |
| tests2.cpp:109:12:109:17 | call to getenv | tests2.cpp:109:6:109:8 | ptr [post update] |
| tests2.cpp:111:14:111:15 | c1 [read] [ptr] | tests2.cpp:111:14:111:19 | (const char *)... |
| tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:39:19:39:22 | (const void *)... |
| tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:39:19:39:22 | path |
| tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:43:20:43:23 | (const void *)... |
| tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:43:20:43:23 | path |
| tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:76:19:76:22 | (const void *)... |
| tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:76:19:76:22 | path |
| tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:80:20:80:23 | (const void *)... |
| tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:80:20:80:23 | path |
| tests_sysconf.cpp:36:21:36:27 | confstr output argument | tests_sysconf.cpp:39:19:39:25 | (const void *)... |
| tests_sysconf.cpp:36:21:36:27 | confstr output argument | tests_sysconf.cpp:39:19:39:25 | pathbuf |
nodes
| tests2.cpp:63:13:63:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:63:13:63:18 | call to getenv | semmle.label | call to getenv |
@@ -21,27 +32,49 @@ nodes
| tests2.cpp:65:13:65:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:65:13:65:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:65:13:65:30 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:76:18:76:38 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:79:14:79:19 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:89:42:89:45 | str1 | semmle.label | str1 |
| tests2.cpp:91:14:91:17 | str1 | semmle.label | str1 |
| tests2.cpp:99:8:99:15 | call to getpwuid | semmle.label | call to getpwuid |
| tests2.cpp:100:14:100:15 | pw | semmle.label | pw |
| tests2.cpp:107:3:107:4 | c1 [post update] [ptr] | semmle.label | c1 [post update] [ptr] |
| tests2.cpp:107:6:107:8 | ptr [post update] | semmle.label | ptr [post update] |
| tests2.cpp:107:12:107:17 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:109:14:109:15 | c1 [read] [ptr] | semmle.label | c1 [read] [ptr] |
| tests2.cpp:109:14:109:19 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:66:13:66:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:66:13:66:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:66:13:66:34 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:78:18:78:38 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:81:14:81:19 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:91:42:91:45 | str1 | semmle.label | str1 |
| tests2.cpp:93:14:93:17 | str1 | semmle.label | str1 |
| tests2.cpp:101:8:101:15 | call to getpwuid | semmle.label | call to getpwuid |
| tests2.cpp:102:14:102:15 | pw | semmle.label | pw |
| tests2.cpp:109:3:109:4 | c1 [post update] [ptr] | semmle.label | c1 [post update] [ptr] |
| tests2.cpp:109:6:109:8 | ptr [post update] | semmle.label | ptr [post update] |
| tests2.cpp:109:12:109:17 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:111:14:111:15 | c1 [read] [ptr] | semmle.label | c1 [read] [ptr] |
| tests2.cpp:111:14:111:19 | (const char *)... | semmle.label | (const char *)... |
| tests_sockets.cpp:26:15:26:20 | call to getenv | semmle.label | call to getenv |
| tests_sockets.cpp:39:19:39:22 | (const void *)... | semmle.label | (const void *)... |
| tests_sockets.cpp:39:19:39:22 | path | semmle.label | path |
| tests_sockets.cpp:43:20:43:23 | (const void *)... | semmle.label | (const void *)... |
| tests_sockets.cpp:43:20:43:23 | path | semmle.label | path |
| tests_sockets.cpp:63:15:63:20 | call to getenv | semmle.label | call to getenv |
| tests_sockets.cpp:76:19:76:22 | (const void *)... | semmle.label | (const void *)... |
| tests_sockets.cpp:76:19:76:22 | path | semmle.label | path |
| tests_sockets.cpp:80:20:80:23 | (const void *)... | semmle.label | (const void *)... |
| tests_sockets.cpp:80:20:80:23 | path | semmle.label | path |
| tests_sysconf.cpp:36:21:36:27 | confstr output argument | semmle.label | confstr output argument |
| tests_sysconf.cpp:39:19:39:25 | (const void *)... | semmle.label | (const void *)... |
| tests_sysconf.cpp:39:19:39:25 | pathbuf | semmle.label | pathbuf |
subpaths
#select
| tests2.cpp:63:13:63:18 | call to getenv | tests2.cpp:63:13:63:18 | call to getenv | tests2.cpp:63:13:63:18 | call to getenv | This operation exposes system data from $@. | tests2.cpp:63:13:63:18 | call to getenv | call to getenv |
| tests2.cpp:64:13:64:18 | call to getenv | tests2.cpp:64:13:64:18 | call to getenv | tests2.cpp:64:13:64:18 | call to getenv | This operation exposes system data from $@. | tests2.cpp:64:13:64:18 | call to getenv | call to getenv |
| tests2.cpp:65:13:65:18 | call to getenv | tests2.cpp:65:13:65:18 | call to getenv | tests2.cpp:65:13:65:18 | call to getenv | This operation exposes system data from $@. | tests2.cpp:65:13:65:18 | call to getenv | call to getenv |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | This operation exposes system data from $@. | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | This operation exposes system data from $@. | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:79:14:79:19 | (const char *)... | tests2.cpp:76:18:76:38 | call to mysql_get_client_info | tests2.cpp:79:14:79:19 | (const char *)... | This operation exposes system data from $@. | tests2.cpp:76:18:76:38 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:91:14:91:17 | str1 | tests2.cpp:89:42:89:45 | str1 | tests2.cpp:91:14:91:17 | str1 | This operation exposes system data from $@. | tests2.cpp:89:42:89:45 | str1 | str1 |
| tests2.cpp:100:14:100:15 | pw | tests2.cpp:99:8:99:15 | call to getpwuid | tests2.cpp:100:14:100:15 | pw | This operation exposes system data from $@. | tests2.cpp:99:8:99:15 | call to getpwuid | call to getpwuid |
| tests2.cpp:109:14:109:19 | (const char *)... | tests2.cpp:107:12:107:17 | call to getenv | tests2.cpp:109:14:109:19 | (const char *)... | This operation exposes system data from $@. | tests2.cpp:107:12:107:17 | call to getenv | call to getenv |
| tests2.cpp:66:13:66:18 | call to getenv | tests2.cpp:66:13:66:18 | call to getenv | tests2.cpp:66:13:66:18 | call to getenv | This operation exposes system data from $@. | tests2.cpp:66:13:66:18 | call to getenv | call to getenv |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | This operation exposes system data from $@. | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | This operation exposes system data from $@. | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:81:14:81:19 | (const char *)... | tests2.cpp:78:18:78:38 | call to mysql_get_client_info | tests2.cpp:81:14:81:19 | (const char *)... | This operation exposes system data from $@. | tests2.cpp:78:18:78:38 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:93:14:93:17 | str1 | tests2.cpp:91:42:91:45 | str1 | tests2.cpp:93:14:93:17 | str1 | This operation exposes system data from $@. | tests2.cpp:91:42:91:45 | str1 | str1 |
| tests2.cpp:102:14:102:15 | pw | tests2.cpp:101:8:101:15 | call to getpwuid | tests2.cpp:102:14:102:15 | pw | This operation exposes system data from $@. | tests2.cpp:101:8:101:15 | call to getpwuid | call to getpwuid |
| tests2.cpp:111:14:111:19 | (const char *)... | tests2.cpp:109:12:109:17 | call to getenv | tests2.cpp:111:14:111:19 | (const char *)... | This operation exposes system data from $@. | tests2.cpp:109:12:109:17 | call to getenv | call to getenv |
| tests_sockets.cpp:39:19:39:22 | path | tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:39:19:39:22 | path | This operation exposes system data from $@. | tests_sockets.cpp:26:15:26:20 | call to getenv | call to getenv |
| tests_sockets.cpp:43:20:43:23 | path | tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:43:20:43:23 | path | This operation exposes system data from $@. | tests_sockets.cpp:26:15:26:20 | call to getenv | call to getenv |
| tests_sockets.cpp:76:19:76:22 | path | tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:76:19:76:22 | path | This operation exposes system data from $@. | tests_sockets.cpp:63:15:63:20 | call to getenv | call to getenv |
| tests_sockets.cpp:80:20:80:23 | path | tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:80:20:80:23 | path | This operation exposes system data from $@. | tests_sockets.cpp:63:15:63:20 | call to getenv | call to getenv |
| tests_sysconf.cpp:39:19:39:25 | pathbuf | tests_sysconf.cpp:36:21:36:27 | confstr output argument | tests_sysconf.cpp:39:19:39:25 | pathbuf | This operation exposes system data from $@. | tests_sysconf.cpp:36:21:36:27 | confstr output argument | confstr output argument |

View File

@@ -0,0 +1,109 @@
edges
| tests.cpp:48:15:48:20 | call to getenv | tests.cpp:48:15:48:36 | (const char *)... |
| tests.cpp:49:15:49:20 | call to getenv | tests.cpp:49:15:49:36 | (const char *)... |
| tests.cpp:50:15:50:20 | call to getenv | tests.cpp:50:15:50:36 | (const char *)... |
| tests.cpp:57:18:57:23 | call to getenv | tests.cpp:57:18:57:39 | (const char_type *)... |
| tests.cpp:58:41:58:46 | call to getenv | tests.cpp:58:41:58:62 | (const char_type *)... |
| tests.cpp:59:43:59:48 | call to getenv | tests.cpp:59:43:59:64 | (const char *)... |
| tests.cpp:86:29:86:31 | *msg | tests.cpp:88:15:88:17 | msg |
| tests.cpp:86:29:86:31 | msg | tests.cpp:88:15:88:17 | msg |
| tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:34 | (const char *)... |
| tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:34 | call to getenv |
| tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:34 | call to getenv indirection |
| tests.cpp:97:13:97:34 | call to getenv | tests.cpp:86:29:86:31 | msg |
| tests.cpp:97:13:97:34 | call to getenv indirection | tests.cpp:86:29:86:31 | *msg |
| tests.cpp:107:30:107:32 | *msg | tests.cpp:111:15:111:17 | tmp |
| tests.cpp:107:30:107:32 | msg | tests.cpp:111:15:111:17 | tmp |
| tests.cpp:114:30:114:32 | *msg | tests.cpp:119:7:119:12 | (const char *)... |
| tests.cpp:114:30:114:32 | msg | tests.cpp:119:7:119:12 | (const char *)... |
| tests.cpp:122:30:122:32 | *msg | tests.cpp:124:15:124:17 | msg |
| tests.cpp:122:30:122:32 | msg | tests.cpp:124:15:124:17 | msg |
| tests.cpp:131:14:131:19 | call to getenv | tests.cpp:131:14:131:35 | call to getenv |
| tests.cpp:131:14:131:19 | call to getenv | tests.cpp:131:14:131:35 | call to getenv indirection |
| tests.cpp:131:14:131:35 | call to getenv | tests.cpp:107:30:107:32 | msg |
| tests.cpp:131:14:131:35 | call to getenv indirection | tests.cpp:107:30:107:32 | *msg |
| tests.cpp:132:14:132:19 | call to getenv | tests.cpp:132:14:132:35 | call to getenv |
| tests.cpp:132:14:132:19 | call to getenv | tests.cpp:132:14:132:35 | call to getenv indirection |
| tests.cpp:132:14:132:35 | call to getenv | tests.cpp:114:30:114:32 | msg |
| tests.cpp:132:14:132:35 | call to getenv indirection | tests.cpp:114:30:114:32 | *msg |
| tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:35 | (const char *)... |
| tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:35 | call to getenv |
| tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:35 | call to getenv indirection |
| tests.cpp:133:14:133:35 | call to getenv | tests.cpp:122:30:122:32 | msg |
| tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:122:30:122:32 | *msg |
| tests_passwd.cpp:16:8:16:15 | call to getpwnam | tests_passwd.cpp:18:29:18:31 | pwd |
| tests_passwd.cpp:16:8:16:15 | call to getpwnam | tests_passwd.cpp:19:26:19:28 | pwd |
nodes
| tests.cpp:48:15:48:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:48:15:48:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:48:15:48:36 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:49:15:49:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:49:15:49:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:49:15:49:36 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:50:15:50:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:50:15:50:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:50:15:50:36 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:57:18:57:23 | call to getenv | semmle.label | call to getenv |
| tests.cpp:57:18:57:23 | call to getenv | semmle.label | call to getenv |
| tests.cpp:57:18:57:39 | (const char_type *)... | semmle.label | (const char_type *)... |
| tests.cpp:58:41:58:46 | call to getenv | semmle.label | call to getenv |
| tests.cpp:58:41:58:46 | call to getenv | semmle.label | call to getenv |
| tests.cpp:58:41:58:62 | (const char_type *)... | semmle.label | (const char_type *)... |
| tests.cpp:59:43:59:48 | call to getenv | semmle.label | call to getenv |
| tests.cpp:59:43:59:48 | call to getenv | semmle.label | call to getenv |
| tests.cpp:59:43:59:64 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:86:29:86:31 | *msg | semmle.label | *msg |
| tests.cpp:86:29:86:31 | msg | semmle.label | msg |
| tests.cpp:88:15:88:17 | msg | semmle.label | msg |
| tests.cpp:97:13:97:18 | call to getenv | semmle.label | call to getenv |
| tests.cpp:97:13:97:18 | call to getenv | semmle.label | call to getenv |
| tests.cpp:97:13:97:34 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:97:13:97:34 | call to getenv | semmle.label | call to getenv |
| tests.cpp:97:13:97:34 | call to getenv indirection | semmle.label | call to getenv indirection |
| tests.cpp:107:30:107:32 | *msg | semmle.label | *msg |
| tests.cpp:107:30:107:32 | msg | semmle.label | msg |
| tests.cpp:111:15:111:17 | tmp | semmle.label | tmp |
| tests.cpp:114:30:114:32 | *msg | semmle.label | *msg |
| tests.cpp:114:30:114:32 | msg | semmle.label | msg |
| tests.cpp:119:7:119:12 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:122:30:122:32 | *msg | semmle.label | *msg |
| tests.cpp:122:30:122:32 | msg | semmle.label | msg |
| tests.cpp:124:15:124:17 | msg | semmle.label | msg |
| tests.cpp:131:14:131:19 | call to getenv | semmle.label | call to getenv |
| tests.cpp:131:14:131:35 | call to getenv | semmle.label | call to getenv |
| tests.cpp:131:14:131:35 | call to getenv indirection | semmle.label | call to getenv indirection |
| tests.cpp:132:14:132:19 | call to getenv | semmle.label | call to getenv |
| tests.cpp:132:14:132:35 | call to getenv | semmle.label | call to getenv |
| tests.cpp:132:14:132:35 | call to getenv indirection | semmle.label | call to getenv indirection |
| tests.cpp:133:14:133:19 | call to getenv | semmle.label | call to getenv |
| tests.cpp:133:14:133:19 | call to getenv | semmle.label | call to getenv |
| tests.cpp:133:14:133:35 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:133:14:133:35 | call to getenv | semmle.label | call to getenv |
| tests.cpp:133:14:133:35 | call to getenv indirection | semmle.label | call to getenv indirection |
| tests_passwd.cpp:16:8:16:15 | call to getpwnam | semmle.label | call to getpwnam |
| tests_passwd.cpp:18:29:18:31 | pwd | semmle.label | pwd |
| tests_passwd.cpp:19:26:19:28 | pwd | semmle.label | pwd |
subpaths
#select
| tests.cpp:48:15:48:20 | call to getenv | tests.cpp:48:15:48:20 | call to getenv | tests.cpp:48:15:48:20 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:48:15:48:20 | call to getenv | call to getenv |
| tests.cpp:48:15:48:36 | (const char *)... | tests.cpp:48:15:48:20 | call to getenv | tests.cpp:48:15:48:36 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:48:15:48:20 | call to getenv | call to getenv |
| tests.cpp:49:15:49:20 | call to getenv | tests.cpp:49:15:49:20 | call to getenv | tests.cpp:49:15:49:20 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:49:15:49:20 | call to getenv | call to getenv |
| tests.cpp:49:15:49:36 | (const char *)... | tests.cpp:49:15:49:20 | call to getenv | tests.cpp:49:15:49:36 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:49:15:49:20 | call to getenv | call to getenv |
| tests.cpp:50:15:50:20 | call to getenv | tests.cpp:50:15:50:20 | call to getenv | tests.cpp:50:15:50:20 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:50:15:50:20 | call to getenv | call to getenv |
| tests.cpp:50:15:50:36 | (const char *)... | tests.cpp:50:15:50:20 | call to getenv | tests.cpp:50:15:50:36 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:50:15:50:20 | call to getenv | call to getenv |
| tests.cpp:57:18:57:23 | call to getenv | tests.cpp:57:18:57:23 | call to getenv | tests.cpp:57:18:57:23 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:57:18:57:23 | call to getenv | call to getenv |
| tests.cpp:57:18:57:39 | (const char_type *)... | tests.cpp:57:18:57:23 | call to getenv | tests.cpp:57:18:57:39 | (const char_type *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:57:18:57:23 | call to getenv | call to getenv |
| tests.cpp:58:41:58:46 | call to getenv | tests.cpp:58:41:58:46 | call to getenv | tests.cpp:58:41:58:46 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:58:41:58:46 | call to getenv | call to getenv |
| tests.cpp:58:41:58:62 | (const char_type *)... | tests.cpp:58:41:58:46 | call to getenv | tests.cpp:58:41:58:62 | (const char_type *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:58:41:58:46 | call to getenv | call to getenv |
| tests.cpp:59:43:59:48 | call to getenv | tests.cpp:59:43:59:48 | call to getenv | tests.cpp:59:43:59:48 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:59:43:59:48 | call to getenv | call to getenv |
| tests.cpp:59:43:59:64 | (const char *)... | tests.cpp:59:43:59:48 | call to getenv | tests.cpp:59:43:59:64 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:59:43:59:48 | call to getenv | call to getenv |
| tests.cpp:88:15:88:17 | msg | tests.cpp:97:13:97:18 | call to getenv | tests.cpp:88:15:88:17 | msg | This operation potentially exposes sensitive system data from $@. | tests.cpp:97:13:97:18 | call to getenv | call to getenv |
| tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:18 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:97:13:97:18 | call to getenv | call to getenv |
| tests.cpp:97:13:97:34 | (const char *)... | tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:34 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:97:13:97:18 | call to getenv | call to getenv |
| tests.cpp:111:15:111:17 | tmp | tests.cpp:131:14:131:19 | call to getenv | tests.cpp:111:15:111:17 | tmp | This operation potentially exposes sensitive system data from $@. | tests.cpp:131:14:131:19 | call to getenv | call to getenv |
| tests.cpp:119:7:119:12 | (const char *)... | tests.cpp:132:14:132:19 | call to getenv | tests.cpp:119:7:119:12 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:132:14:132:19 | call to getenv | call to getenv |
| tests.cpp:124:15:124:17 | msg | tests.cpp:133:14:133:19 | call to getenv | tests.cpp:124:15:124:17 | msg | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:19 | call to getenv | call to getenv |
| tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:19 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:19 | call to getenv | call to getenv |
| tests.cpp:133:14:133:35 | (const char *)... | tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:35 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:19 | call to getenv | call to getenv |
| tests_passwd.cpp:18:29:18:31 | pwd | tests_passwd.cpp:16:8:16:15 | call to getpwnam | tests_passwd.cpp:18:29:18:31 | pwd | This operation potentially exposes sensitive system data from $@. | tests_passwd.cpp:16:8:16:15 | call to getpwnam | call to getpwnam |
| tests_passwd.cpp:19:26:19:28 | pwd | tests_passwd.cpp:16:8:16:15 | call to getpwnam | tests_passwd.cpp:19:26:19:28 | pwd | This operation potentially exposes sensitive system data from $@. | tests_passwd.cpp:16:8:16:15 | call to getpwnam | call to getpwnam |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-497/PotentiallyExposedSystemData.ql

View File

@@ -0,0 +1,134 @@
// test cases for rule CWE-497
// library functions etc
#include "tests.h"
typedef struct {} FILE;
FILE *stdout;
int puts(const char *s);
int printf(const char *format, ...);
int sprintf(char *s, const char *format, ...);
int snprintf(char *s, size_t n, const char *format, ...);
size_t strlen(const char *s);
char *getenv(const char *name);
extern std::ostream someotherostream;
#define NULL (0)
// test cases
void test1()
{
std::ostream cout_copy = std::cout;
std::cout << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable
std::cerr << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable
std::clog << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable
someotherostream << getenv("SECRET_TOKEN"); // GOOD: not output
cout_copy << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable [NOT DETECTED]
std::cout << getenv("USERPROFILE"); // BAD: outputs PATH environment variable [NOT DETECTED]
std::cout << getenv("PATH"); // BAD: outputs PATH environment variable [NOT DETECTED]
std::cout.write(getenv("SECRET_TOKEN"), strlen(getenv("SECRET_TOKEN"))); // BAD: outputs SECRET_TOKEN environment variable
(std::cout << "SECRET_TOKEN = ").write(getenv("SECRET_TOKEN"), strlen(getenv("SECRET_TOKEN"))); // BAD: outputs SECRET_TOKEN environment variable
std::cout.write("SECRET_TOKEN = ", 7) << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable
}
char *global_token = getenv("SECRET_TOKEN");
char *global_other = "Hello, world!";
void test2(bool cond)
{
char *maybe;
maybe = cond ? global_token : global_other;
printf("token = '%s'\n", global_token); // BAD: outputs SECRET_TOKEN environment variable [NOT DETECTED]
printf("other = '%s'\n", global_other);
printf("maybe = '%s'\n", maybe); // BAD: may output SECRET_TOKEN environment variable [NOT DETECTED]
}
void test3()
{
char *path_string = getenv("PATH");
char buf[4096];
// ...
snprintf(buf, 4096, "invalid path '%s'\n", path_string);
puts(buf); // BAD: outputs PATH environment variable [NOT DETECTED]
}
void myOutputFn(const char *msg)
{
printf("%s", msg);
}
void myOtherFn(const char *msg)
{
}
void test4()
{
myOutputFn(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
myOtherFn(getenv("SECRET_TOKEN")); // GOOD: does not output anything.
}
void myOutputFn2(const char *msg)
{
msg = "";
printf("%s", msg);
}
void myOutputFn3(const char *msg)
{
const char *tmp = msg;
printf("%s", tmp);
}
void myOutputFn4(const char *msg)
{
char buffer[4096];
sprintf(buffer, "log: %s\n", msg);
puts(buffer);
}
void myOutputFn5(const char *msg)
{
printf("%s", msg);
msg = "";
}
void test5()
{
myOutputFn2(getenv("SECRET_TOKEN")); // GOOD: myOutputFn2 doesn't actually output the parameter
myOutputFn3(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
myOutputFn4(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
myOutputFn5(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
}

View File

@@ -0,0 +1,25 @@
typedef unsigned long size_t;
namespace std
{
typedef size_t streamsize;
template<class charT> struct char_traits;
template <class charT, class traits = char_traits<charT> >
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
typedef charT char_type;
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
basic_ostream<charT, traits>& operator<<(int n);
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
typedef basic_ostream<char> ostream;
extern ostream cout;
extern ostream cerr;
extern ostream clog;
}

View File

@@ -2,24 +2,24 @@
// library functions etc
#include "tests.h"
char *getenv(const char *name);
char *strcpy(char *s1, const char *s2);
namespace std
{
template<class charT> struct char_traits;
template <class charT, class traits = char_traits<charT> >
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
typedef basic_ostream<char> ostream;
extern ostream cout;
}
int socket(int p1, int p2, int p3);
void send(int sock, const char *buffer, int p3, int p4);
@@ -63,10 +63,12 @@ void test1()
send(sock, getenv("HOME"), val(), val()); // BAD
send(sock, getenv("PATH"), val(), val()); // BAD
send(sock, getenv("USERNAME"), val(), val()); // BAD
send(sock, getenv("APP_PASSWORD"), val(), val()); // BAD
send(sock, getenv("HARMLESS"), val(), val()); // GOOD: harmless information
send(sock, "HOME", val(), val()); // GOOD: not system data
send(sock, "PATH", val(), val()); // GOOD: not system data
send(sock, "USERNAME", val(), val()); // GOOD: not system data
send(sock, "APP_PASSWORD", val(), val()); // GOOD: not system data
send(sock, "HARMLESS", val(), val()); // GOOD: not system data
// tests for `mysql_get_client_info`, including via a global

View File

@@ -0,0 +1,21 @@
int printf(const char *format, ...);
struct passwd {
char *pw_passwd;
char *pw_dir;
// ...
};
struct passwd *getpwnam(const char *name);
void test6(char *username)
{
passwd *pwd;
pwd = getpwnam(username);
printf("pw_passwd = %s\n", pwd->pw_passwd); // BAD
printf("pw_dir = %s\n", pwd->pw_dir); // BAD
printf("sizeof(passwd) = %i\n", sizeof(passwd)); // GOOD
}

View File

@@ -0,0 +1,84 @@
typedef unsigned long size_t;
size_t strlen(const char *s);
char *getenv(const char *name);
#define AF_INET (2)
#define SOCK_STREAM (1)
struct sockaddr {
int sa_family;
// ...
};
int socket(int domain, int type, int protocol);
int connect(int socket, const struct sockaddr *address, size_t address_len);
size_t send(int socket, const void *buffer, size_t length, int flags);
int write(int handle, const void *buffer, size_t length);
void test_sockets1()
{
int sockfd;
sockaddr addr_remote;
char *msg = "Hello, world!";
char *path = getenv("PATH");
// create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) return;
// connect socket to a remote address
addr_remote.sa_family = AF_INET;
// ...
if (connect(sockfd, &addr_remote, sizeof(addr_remote)) != 0) return;
// send something using 'send'
if (send(sockfd, msg, strlen(msg) + 1, 0) < 0) return; // GOOD
if (send(sockfd, path, strlen(path) + 1, 0) < 0) return; // BAD
// send something using 'write'
if (write(sockfd, msg, strlen(msg) + 1) < 0) return; // GOOD
if (write(sockfd, path, strlen(path) + 1) < 0) return; // BAD
// clean up
// ...
}
int mksocket()
{
int fd;
fd = socket(AF_INET, SOCK_STREAM, 0);
return fd;
}
void test_sockets2()
{
int sockfd;
sockaddr addr_remote;
char *msg = "Hello, world!";
char *path = getenv("PATH");
// create socket
sockfd = mksocket();
if (sockfd < 0) return;
// connect socket to a remote address
addr_remote.sa_family = AF_INET;
// ...
if (connect(sockfd, &addr_remote, sizeof(addr_remote)) != 0) return;
// send something using 'send'
if (send(sockfd, msg, strlen(msg) + 1, 0) < 0) return; // GOOD
if (send(sockfd, path, strlen(path) + 1, 0) < 0) return; // BAD
// send something using 'write'
if (write(sockfd, msg, strlen(msg) + 1) < 0) return; // GOOD
if (write(sockfd, path, strlen(path) + 1) < 0) return; // BAD
// clean up
// ...
}

View File

@@ -0,0 +1,41 @@
typedef unsigned long size_t;
typedef signed long ssize_t;
void *malloc(size_t size);
#define NULL (0)
int printf(const char *format, ...);
size_t strlen(const char *s);
int get_fd();
int write(int handle, const void *buffer, size_t length);
long sysconf(int name);
#define _SC_CHILD_MAX (2)
size_t confstr(int name, char *buffer, size_t length);
#define _CS_PATH (1)
void test_sc_1()
{
int value = sysconf(_SC_CHILD_MAX);
printf("_SC_CHILD_MAX = %i\n", _SC_CHILD_MAX); // GOOD
printf("_SC_CHILD_MAX = %i\n", value); // BAD [NOT DETECTED]
}
void test_sc_2()
{
char *pathbuf;
size_t n;
n = confstr(_CS_PATH, NULL, (size_t)0);
pathbuf = (char *)malloc(n);
if (pathbuf != NULL)
{
confstr(_CS_PATH, pathbuf, n);
printf("path: %s", pathbuf); // BAD [NOT DETECTED]
write(get_fd(), pathbuf, strlen(pathbuf)); // BAD
}
}

View File

@@ -1,6 +1,7 @@
/** Provides classes for collections. */
import csharp
import semmle.code.csharp.frameworks.system.Collections
private string modifyMethodName() {
result =
@@ -66,6 +67,12 @@ class CollectionType extends RefType {
}
}
/** Holds if `t` is a collection type. */
predicate isCollectionType(ValueOrRefType t) {
t.getABaseType*() instanceof SystemCollectionsIEnumerableInterface and
not t instanceof StringType
}
/** An object creation that creates an empty collection. */
class EmptyCollectionCreation extends ObjectCreation {
EmptyCollectionCreation() {

View File

@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
this.dominates(result.getAPredecessor()) and
not this.strictlyDominates(result)
this.getASuccessor() = result and
not this.immediatelyDominates(result)
or
exists(IRBlock prev | result = prev.dominanceFrontier() |
this.immediatelyDominates(prev) and
not this.immediatelyDominates(result)
)
}
/**
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock postDominanceFrontier() {
this.postDominates(result.getASuccessor()) and
not this.strictlyPostDominates(result)
this.getAPredecessor() = result and
not this.immediatelyPostDominates(result)
or
exists(IRBlock prev | result = prev.postDominanceFrontier() |
this.immediatelyPostDominates(prev) and
not this.immediatelyPostDominates(result)
)
}
/**

View File

@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
this.dominates(result.getAPredecessor()) and
not this.strictlyDominates(result)
this.getASuccessor() = result and
not this.immediatelyDominates(result)
or
exists(IRBlock prev | result = prev.dominanceFrontier() |
this.immediatelyDominates(prev) and
not this.immediatelyDominates(result)
)
}
/**
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock postDominanceFrontier() {
this.postDominates(result.getASuccessor()) and
not this.strictlyPostDominates(result)
this.getAPredecessor() = result and
not this.immediatelyPostDominates(result)
or
exists(IRBlock prev | result = prev.postDominanceFrontier() |
this.immediatelyPostDominates(prev) and
not this.immediatelyPostDominates(result)
)
}
/**

View File

@@ -1,6 +1,7 @@
import csharp
import semmle.code.csharp.dataflow.internal.DataFlowPrivate
private import semmle.code.csharp.commons.Util
private import semmle.code.csharp.commons.Collections
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
@@ -28,14 +29,8 @@ predicate asPartialModel = Csv::asPartialModel/1;
*/
predicate isRelevantType(Type t) { not t instanceof Enum }
private predicate isPrimitiveTypeUsedForBulkData(Type t) {
t.getName().regexpMatch("byte|char|Byte|Char")
}
private string parameterAccess(Parameter p) {
if
p.getType() instanceof ArrayType and
not isPrimitiveTypeUsedForBulkData(p.getType().(ArrayType).getElementType())
if isCollectionType(p.getType())
then result = "Argument[" + p.getPosition() + "].Element"
else result = "Argument[" + p.getPosition() + "]"
}

View File

@@ -1,6 +1,5 @@
| Summaries;BasicFlow;false;AssignFieldToArray;(System.Object[]);Argument[Qualifier];Argument[0].Element;taint |
| Summaries;BasicFlow;false;AssignToArray;(System.Int32,System.Int32[]);Argument[0];Argument[1].Element;taint |
| Summaries;BasicFlow;false;ReturnArrayElement;(System.Int32[]);Argument[0].Element;ReturnValue;taint |
| NoSummaries;PublicClassFlow;false;PublicReturn;(System.Int32);Argument[0];ReturnValue;taint |
| Summaries;BaseClassFlow;true;ReturnParam;(System.Int32);Argument[0];ReturnValue;taint |
| Summaries;BasicFlow;false;ReturnField;();Argument[Qualifier];ReturnValue;taint |
| Summaries;BasicFlow;false;ReturnParam0;(System.String,System.Object);Argument[0];ReturnValue;taint |
| Summaries;BasicFlow;false;ReturnParam1;(System.String,System.Object);Argument[1];ReturnValue;taint |
@@ -9,3 +8,23 @@
| Summaries;BasicFlow;false;ReturnSubstring;(System.String);Argument[0];ReturnValue;taint |
| Summaries;BasicFlow;false;ReturnThis;(System.Object);Argument[Qualifier];ReturnValue;value |
| Summaries;BasicFlow;false;SetField;(System.String);Argument[0];Argument[Qualifier];taint |
| Summaries;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List<System.String>);Argument[Qualifier];Argument[0].Element;taint |
| Summaries;CollectionFlow;false;AddToList;(System.Collections.Generic.List<System.Object>,System.Object);Argument[1];Argument[0].Element;taint |
| Summaries;CollectionFlow;false;AssignFieldToArray;(System.Object[]);Argument[Qualifier];Argument[0].Element;taint |
| Summaries;CollectionFlow;false;AssignToArray;(System.Int32,System.Int32[]);Argument[0];Argument[1].Element;taint |
| Summaries;CollectionFlow;false;ReturnArrayElement;(System.Int32[]);Argument[0].Element;ReturnValue;taint |
| Summaries;CollectionFlow;false;ReturnFieldInAList;();Argument[Qualifier];ReturnValue;taint |
| Summaries;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List<System.Object>);Argument[0].Element;ReturnValue;taint |
| Summaries;DerivedClass1Flow;false;ReturnParam1;(System.Int32,System.Int32);Argument[1];ReturnValue;taint |
| Summaries;DerivedClass2Flow;false;ReturnParam0;(System.Int32,System.Int32);Argument[0];ReturnValue;taint |
| Summaries;DerivedClass2Flow;false;ReturnParam;(System.Int32);Argument[0];ReturnValue;taint |
| Summaries;GenericFlow<>;false;AddFieldToGenericList;(System.Collections.Generic.List<T>);Argument[Qualifier];Argument[0].Element;taint |
| Summaries;GenericFlow<>;false;AddToGenericList<>;(System.Collections.Generic.List<S>,S);Argument[1];Argument[0].Element;taint |
| Summaries;GenericFlow<>;false;ReturnFieldInGenericList;();Argument[Qualifier];ReturnValue;taint |
| Summaries;GenericFlow<>;false;ReturnGenericElement<>;(System.Collections.Generic.List<S>);Argument[0].Element;ReturnValue;taint |
| Summaries;GenericFlow<>;false;ReturnGenericField;();Argument[Qualifier];ReturnValue;taint |
| Summaries;GenericFlow<>;false;ReturnGenericParam<>;(S);Argument[0];ReturnValue;taint |
| Summaries;GenericFlow<>;false;SetGenericField;(T);Argument[0];Argument[Qualifier];taint |
| Summaries;IEnumerableFlow;false;ReturnFieldInIEnumerable;();Argument[Qualifier];ReturnValue;taint |
| Summaries;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable<System.String>);Argument[0].Element;ReturnValue;taint |
| Summaries;IEnumerableFlow;false;ReturnIEnumerableElement;(System.Collections.Generic.IEnumerable<System.Object>);Argument[0].Element;ReturnValue;taint |

View File

@@ -0,0 +1,45 @@
using System;
namespace NoSummaries;
// Single class with a method that produces a flow summary.
// Just to prove that, if a method like this is correctly exposed, a flow summary will be captured.
public class PublicClassFlow
{
public int PublicReturn(int input)
{
return input;
}
}
public sealed class PublicClassNoFlow
{
private int PrivateReturn(int input)
{
return input;
}
internal int InternalReturn(int input)
{
return input;
}
private class PrivateClassNoFlow
{
public int ReturnParam(int input)
{
return input;
}
}
private class PrivateClassNestedPublicClassNoFlow
{
public class NestedPublicClassFlow
{
public int ReturnParam(int input)
{
return input;
}
}
}
}

View File

@@ -1,4 +1,6 @@
using System;
using System.Linq;
using System.Collections.Generic;
namespace Summaries;
@@ -31,6 +33,21 @@ public class BasicFlow
return s.Substring(0, 1);
}
public void SetField(string s)
{
tainted = s;
}
public string ReturnField()
{
return tainted;
}
}
public class CollectionFlow
{
private string tainted;
public int ReturnArrayElement(int[] input)
{
return input[0];
@@ -41,18 +58,117 @@ public class BasicFlow
target[0] = data;
}
public void SetField(string s)
{
tainted = s;
}
public string ReturnField()
{
return tainted;
}
public void AssignFieldToArray(object[] target)
{
target[0] = tainted;
}
public object ReturnListElement(List<object> input)
{
return input[0];
}
public void AddToList(List<object> input, object data)
{
input.Add(data);
}
public void AddFieldToList(List<string> input)
{
input.Add(tainted);
}
public List<string> ReturnFieldInAList()
{
return new List<string> { tainted };
}
}
public class IEnumerableFlow
{
private string tainted;
public IEnumerable<string> ReturnIEnumerable(IEnumerable<string> input)
{
return input;
}
public object ReturnIEnumerableElement(IEnumerable<object> input)
{
return input.First();
}
public IEnumerable<string> ReturnFieldInIEnumerable()
{
return new List<string> { tainted };
}
}
public class GenericFlow<T>
{
private T tainted;
public void SetGenericField(T t)
{
tainted = t;
}
public T ReturnGenericField()
{
return tainted;
}
public void AddFieldToGenericList(List<T> input)
{
input.Add(tainted);
}
public List<T> ReturnFieldInGenericList()
{
return new List<T> { tainted };
}
public S ReturnGenericParam<S>(S input)
{
return input;
}
public S ReturnGenericElement<S>(List<S> input)
{
return input[0];
}
public void AddToGenericList<S>(List<S> input, S data)
{
input.Add(data);
}
}
public abstract class BaseClassFlow
{
public virtual int ReturnParam(int input)
{
return input;
}
}
public class DerivedClass1Flow : BaseClassFlow
{
public int ReturnParam1(int input0, int input1)
{
return input1;
}
}
public class DerivedClass2Flow : BaseClassFlow
{
public override int ReturnParam(int input)
{
return input;
}
public int ReturnParam0(int input0, int input1)
{
return input0;
}
}

View File

@@ -0,0 +1 @@
semmle-extractor-options: /r:System.Linq.dll

View File

@@ -7,8 +7,8 @@ When analyzing a Go program, CodeQL does not examine the source code for
external packages. To track the flow of untrusted data through a library, you
can create a model of the library.
You can find existing models in the ``ql/src/semmle/go/frameworks/`` folder of the
`CodeQL for Go repository <https://github.com/github/codeql-go/tree/main/ql/src/semmle/go/frameworks>`__.
You can find existing models in the ``ql/lib/semmle/go/frameworks/`` folder of the
`CodeQL for Go repository <https://github.com/github/codeql-go/tree/main/ql/lib/semmle/go/frameworks>`__.
To add a new model, you should make a new file in that folder, named after the library.
Sources
@@ -102,8 +102,8 @@ Data-flow sinks are specified by queries rather than by library models.
However, you can use library models to indicate when functions belong to
special categories. Queries can then use these categories when specifying
sinks. Classes representing these special categories are contained in
``ql/src/semmle/go/Concepts.qll`` in the `CodeQL for Go repository
<https://github.com/github/codeql-go/blob/main/ql/src/semmle/go/Concepts.qll>`__.
``ql/lib/semmle/go/Concepts.qll`` in the `CodeQL for Go repository
<https://github.com/github/codeql-go/blob/main/ql/lib/semmle/go/Concepts.qll>`__.
``Concepts.qll`` includes classes for logger mechanisms,
HTTP response writers, HTTP redirects, and marshaling and unmarshaling
functions.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* There are now QL classes ErrorExpr and ErrorStmt. These may be generated by upgrade or downgrade scripts when databases cannot be fully converted.

View File

@@ -528,6 +528,7 @@ case @stmt.kind of
| 21 = @case
| 22 = @catchclause
| 23 = @yieldstmt
| 24 = @errorstmt
;
#keyset[parent,idx]
@@ -628,6 +629,7 @@ case @expr.kind of
| 71 = @typeannotation
| 72 = @intersectiontypeaccess
| 73 = @switchexpr
| 74 = @errorexpr
;
@classinstancexpr = @newexpr | @lambdaexpr | @memberref

View File

@@ -1,5 +1,6 @@
<dbstats>
<typesizes><e>
<typesizes>
<e>
<k>@compilation</k>
<v>8629</v>
</e>
@@ -21,7 +22,7 @@
</e>
<e>
<k>@location_default</k>
<v>13306607</v>
<v>17430587</v>
</e>
<e>
<k>@file</k>
@@ -149,7 +150,7 @@
</e>
<e>
<k>@emptystmt</k>
<v>886</v>
<v>1562</v>
</e>
<e>
<k>@exprstmt</k>
@@ -191,6 +192,10 @@
<k>@yieldstmt</k>
<v>1</v>
</e>
<e>
<k>@errorstmt</k>
<v>1</v>
</e>
<e>
<k>@arrayaccess</k>
<v>181399</v>
@@ -265,7 +270,7 @@
</e>
<e>
<k>@mulexpr</k>
<v>85898</v>
<v>204610</v>
</e>
<e>
<k>@divexpr</k>
@@ -281,7 +286,7 @@
</e>
<e>
<k>@subexpr</k>
<v>57171</v>
<v>84397</v>
</e>
<e>
<k>@lshiftexpr</k>
@@ -483,6 +488,10 @@
<k>@switchexpr</k>
<v>1</v>
</e>
<e>
<k>@errorexpr</k>
<v>1</v>
</e>
<e>
<k>@localvar</k>
<v>385335</v>
@@ -519,10 +528,6 @@
<k>@javadocTag</k>
<v>335863</v>
</e>
<e>
<k>@javadocText</k>
<v>2503256</v>
</e>
<e>
<k>@xmldtd</k>
<v>569</v>
@@ -531,6 +536,10 @@
<k>@xmlelement</k>
<v>1199832</v>
</e>
<e>
<k>@javadocText</k>
<v>2503256</v>
</e>
<e>
<k>@xmlattribute</k>
<v>1841492</v>
@@ -560,7 +569,8 @@
<v>1</v>
</e>
</typesizes>
<stats><relation>
<stats>
<relation>
<name>compilations</name>
<cardinality>8629</cardinality>
<columnsizes>
@@ -16749,11 +16759,11 @@
</relation>
<relation>
<name>isParenthesized</name>
<cardinality>84274</cardinality>
<cardinality>94666</cardinality>
<columnsizes>
<e>
<k>id</k>
<v>84274</v>
<v>94666</v>
</e>
<e>
<k>parentheses</k>
@@ -16771,7 +16781,7 @@
<b>
<a>1</a>
<b>2</b>
<v>84274</v>
<v>94666</v>
</b>
</bs>
</hist>
@@ -16785,13 +16795,13 @@
<budget>12</budget>
<bs>
<b>
<a>12</a>
<b>13</b>
<a>58</a>
<b>59</b>
<v>2</v>
</b>
<b>
<a>31863</a>
<b>31864</b>
<a>34605</a>
<b>34606</b>
<v>2</v>
</b>
</bs>

View File

@@ -377,6 +377,18 @@ class CompileTimeConstantExpr extends Expr {
/** An expression parent is an element that may have an expression as its child. */
class ExprParent extends @exprparent, Top { }
/**
* An error expression.
*
* These may be generated by upgrade or downgrade scripts when databases
* cannot be fully converted.
*/
class ErrorExpr extends Expr, @errorexpr {
override string toString() { result = "<error expr>" }
override string getAPrimaryQlClass() { result = "ErrorExpr" }
}
/**
* An array access.
*

View File

@@ -59,6 +59,18 @@ class Stmt extends StmtParent, ExprParent, @stmt {
/** A statement parent is any element that can have a statement as its child. */
class StmtParent extends @stmtparent, Top { }
/**
* An error statement.
*
* These may be generated by upgrade or downgrade scripts when databases
* cannot be fully converted.
*/
class ErrorStmt extends Stmt, @errorstmt {
override string toString() { result = "<error stmt>" }
override string getAPrimaryQlClass() { result = "ErrorStmt" }
}
/** A block of statements. */
class BlockStmt extends Stmt, @block {
/** Gets a statement that is an immediate child of this block. */

View File

@@ -0,0 +1,982 @@
/**
* An invocation of the compiler. Note that more than one file may be
* compiled per invocation. For example, this command compiles three
* source files:
*
* javac A.java B.java C.java
*
* The `id` simply identifies the invocation, while `cwd` is the working
* directory from which the compiler was invoked.
*/
compilations(
/**
* An invocation of the compiler. Note that more than one file may
* be compiled per invocation. For example, this command compiles
* three source files:
*
* javac A.java B.java C.java
*/
unique int id : @compilation,
string cwd : string ref
);
/**
* The arguments that were passed to the extractor for a compiler
* invocation. If `id` is for the compiler invocation
*
* javac A.java B.java C.java
*
* then typically there will be rows for
*
* num | arg
* --- | ---
* 0 | *path to extractor*
* 1 | `--javac-args`
* 2 | A.java
* 3 | B.java
* 4 | C.java
*/
#keyset[id, num]
compilation_args(
int id : @compilation ref,
int num : int ref,
string arg : string ref
);
/**
* The source files that are compiled by a compiler invocation.
* If `id` is for the compiler invocation
*
* javac A.java B.java C.java
*
* then there will be rows for
*
* num | arg
* --- | ---
* 0 | A.java
* 1 | B.java
* 2 | C.java
*/
#keyset[id, num]
compilation_compiling_files(
int id : @compilation ref,
int num : int ref,
int file : @file ref
);
/**
* The time taken by the extractor for a compiler invocation.
*
* For each file `num`, there will be rows for
*
* kind | seconds
* ---- | ---
* 1 | CPU seconds used by the extractor frontend
* 2 | Elapsed seconds during the extractor frontend
* 3 | CPU seconds used by the extractor backend
* 4 | Elapsed seconds during the extractor backend
*/
#keyset[id, num, kind]
compilation_time(
int id : @compilation ref,
int num : int ref,
/* kind:
1 = frontend_cpu_seconds
2 = frontend_elapsed_seconds
3 = extractor_cpu_seconds
4 = extractor_elapsed_seconds
*/
int kind : int ref,
float seconds : float ref
);
/**
* An error or warning generated by the extractor.
* The diagnostic message `diagnostic` was generated during compiler
* invocation `compilation`, and is the `file_number_diagnostic_number`th
* message generated while extracting the `file_number`th file of that
* invocation.
*/
#keyset[compilation, file_number, file_number_diagnostic_number]
diagnostic_for(
unique int diagnostic : @diagnostic ref,
int compilation : @compilation ref,
int file_number : int ref,
int file_number_diagnostic_number : int ref
);
/**
* If extraction was successful, then `cpu_seconds` and
* `elapsed_seconds` are the CPU time and elapsed time (respectively)
* that extraction took for compiler invocation `id`.
*/
compilation_finished(
unique int id : @compilation ref,
float cpu_seconds : float ref,
float elapsed_seconds : float ref
);
diagnostics(
unique int id: @diagnostic,
int severity: int ref,
string error_tag: string ref,
string error_message: string ref,
string full_error_message: string ref,
int location: @location_default ref
);
/*
* External artifacts
*/
externalData(
int id : @externalDataElement,
string path : string ref,
int column: int ref,
string value : string ref
);
snapshotDate(
unique date snapshotDate : date ref
);
sourceLocationPrefix(
string prefix : string ref
);
/*
* Duplicate code
*/
duplicateCode(
unique int id : @duplication,
string relativePath : string ref,
int equivClass : int ref
);
similarCode(
unique int id : @similarity,
string relativePath : string ref,
int equivClass : int ref
);
@duplication_or_similarity = @duplication | @similarity
tokens(
int id : @duplication_or_similarity ref,
int offset : int ref,
int beginLine : int ref,
int beginColumn : int ref,
int endLine : int ref,
int endColumn : int ref
);
/*
* SMAP
*/
smap_header(
int outputFileId: @file ref,
string outputFilename: string ref,
string defaultStratum: string ref
);
smap_files(
int outputFileId: @file ref,
string stratum: string ref,
int inputFileNum: int ref,
string inputFileName: string ref,
int inputFileId: @file ref
);
smap_lines(
int outputFileId: @file ref,
string stratum: string ref,
int inputFileNum: int ref,
int inputStartLine: int ref,
int inputLineCount: int ref,
int outputStartLine: int ref,
int outputLineIncrement: int ref
);
/*
* Locations and files
*/
@location = @location_default ;
locations_default(
unique int id: @location_default,
int file: @file ref,
int beginLine: int ref,
int beginColumn: int ref,
int endLine: int ref,
int endColumn: int ref
);
hasLocation(
int locatableid: @locatable ref,
int id: @location ref
);
@sourceline = @locatable ;
#keyset[element_id]
numlines(
int element_id: @sourceline ref,
int num_lines: int ref,
int num_code: int ref,
int num_comment: int ref
);
files(
unique int id: @file,
string name: string ref
);
folders(
unique int id: @folder,
string name: string ref
);
@container = @folder | @file
containerparent(
int parent: @container ref,
unique int child: @container ref
);
/*
* Java
*/
cupackage(
unique int id: @file ref,
int packageid: @package ref
);
#keyset[fileid,keyName]
jarManifestMain(
int fileid: @file ref,
string keyName: string ref,
string value: string ref
);
#keyset[fileid,entryName,keyName]
jarManifestEntries(
int fileid: @file ref,
string entryName: string ref,
string keyName: string ref,
string value: string ref
);
packages(
unique int id: @package,
string nodeName: string ref
);
primitives(
unique int id: @primitive,
string nodeName: string ref
);
modifiers(
unique int id: @modifier,
string nodeName: string ref
);
classes(
unique int id: @class,
string nodeName: string ref,
int parentid: @package ref,
int sourceid: @class ref
);
isRecord(
unique int id: @class ref
);
interfaces(
unique int id: @interface,
string nodeName: string ref,
int parentid: @package ref,
int sourceid: @interface ref
);
fielddecls(
unique int id: @fielddecl,
int parentid: @reftype ref
);
#keyset[fieldId] #keyset[fieldDeclId,pos]
fieldDeclaredIn(
int fieldId: @field ref,
int fieldDeclId: @fielddecl ref,
int pos: int ref
);
fields(
unique int id: @field,
string nodeName: string ref,
int typeid: @type ref,
int parentid: @reftype ref,
int sourceid: @field ref
);
constrs(
unique int id: @constructor,
string nodeName: string ref,
string signature: string ref,
int typeid: @type ref,
int parentid: @reftype ref,
int sourceid: @constructor ref
);
methods(
unique int id: @method,
string nodeName: string ref,
string signature: string ref,
int typeid: @type ref,
int parentid: @reftype ref,
int sourceid: @method ref
);
#keyset[parentid,pos]
params(
unique int id: @param,
int typeid: @type ref,
int pos: int ref,
int parentid: @callable ref,
int sourceid: @param ref
);
paramName(
unique int id: @param ref,
string nodeName: string ref
);
isVarargsParam(
int param: @param ref
);
exceptions(
unique int id: @exception,
int typeid: @type ref,
int parentid: @callable ref
);
isAnnotType(
int interfaceid: @interface ref
);
isAnnotElem(
int methodid: @method ref
);
annotValue(
int parentid: @annotation ref,
int id2: @method ref,
unique int value: @expr ref
);
isEnumType(
int classid: @class ref
);
isEnumConst(
int fieldid: @field ref
);
#keyset[parentid,pos]
typeVars(
unique int id: @typevariable,
string nodeName: string ref,
int pos: int ref,
int kind: int ref, // deprecated
int parentid: @classorinterfaceorcallable ref
);
wildcards(
unique int id: @wildcard,
string nodeName: string ref,
int kind: int ref
);
#keyset[parentid,pos]
typeBounds(
unique int id: @typebound,
int typeid: @reftype ref,
int pos: int ref,
int parentid: @boundedtype ref
);
#keyset[parentid,pos]
typeArgs(
int argumentid: @reftype ref,
int pos: int ref,
int parentid: @classorinterfaceorcallable ref
);
isParameterized(
int memberid: @member ref
);
isRaw(
int memberid: @member ref
);
erasure(
unique int memberid: @member ref,
int erasureid: @member ref
);
#keyset[classid] #keyset[parent]
isAnonymClass(
int classid: @class ref,
int parent: @classinstancexpr ref
);
#keyset[typeid] #keyset[parent]
isLocalClassOrInterface(
int typeid: @classorinterface ref,
int parent: @localtypedeclstmt ref
);
isDefConstr(
int constructorid: @constructor ref
);
#keyset[exprId]
lambdaKind(
int exprId: @lambdaexpr ref,
int bodyKind: int ref
);
arrays(
unique int id: @array,
string nodeName: string ref,
int elementtypeid: @type ref,
int dimension: int ref,
int componenttypeid: @type ref
);
enclInReftype(
unique int child: @reftype ref,
int parent: @reftype ref
);
extendsReftype(
int id1: @reftype ref,
int id2: @classorinterface ref
);
implInterface(
int id1: @classorarray ref,
int id2: @interface ref
);
permits(
int id1: @classorinterface ref,
int id2: @classorinterface ref
);
hasModifier(
int id1: @modifiable ref,
int id2: @modifier ref
);
imports(
unique int id: @import,
int holder: @classorinterfaceorpackage ref,
string name: string ref,
int kind: int ref
);
#keyset[parent,idx]
stmts(
unique int id: @stmt,
int kind: int ref,
int parent: @stmtparent ref,
int idx: int ref,
int bodydecl: @callable ref
);
@stmtparent = @callable | @stmt | @switchexpr;
case @stmt.kind of
0 = @block
| 1 = @ifstmt
| 2 = @forstmt
| 3 = @enhancedforstmt
| 4 = @whilestmt
| 5 = @dostmt
| 6 = @trystmt
| 7 = @switchstmt
| 8 = @synchronizedstmt
| 9 = @returnstmt
| 10 = @throwstmt
| 11 = @breakstmt
| 12 = @continuestmt
| 13 = @emptystmt
| 14 = @exprstmt
| 15 = @labeledstmt
| 16 = @assertstmt
| 17 = @localvariabledeclstmt
| 18 = @localtypedeclstmt
| 19 = @constructorinvocationstmt
| 20 = @superconstructorinvocationstmt
| 21 = @case
| 22 = @catchclause
| 23 = @yieldstmt
;
#keyset[parent,idx]
exprs(
unique int id: @expr,
int kind: int ref,
int typeid: @type ref,
int parent: @exprparent ref,
int idx: int ref
);
callableEnclosingExpr(
unique int id: @expr ref,
int callable_id: @callable ref
);
statementEnclosingExpr(
unique int id: @expr ref,
int statement_id: @stmt ref
);
isParenthesized(
unique int id: @expr ref,
int parentheses: int ref
);
case @expr.kind of
1 = @arrayaccess
| 2 = @arraycreationexpr
| 3 = @arrayinit
| 4 = @assignexpr
| 5 = @assignaddexpr
| 6 = @assignsubexpr
| 7 = @assignmulexpr
| 8 = @assigndivexpr
| 9 = @assignremexpr
| 10 = @assignandexpr
| 11 = @assignorexpr
| 12 = @assignxorexpr
| 13 = @assignlshiftexpr
| 14 = @assignrshiftexpr
| 15 = @assignurshiftexpr
| 16 = @booleanliteral
| 17 = @integerliteral
| 18 = @longliteral
| 19 = @floatingpointliteral
| 20 = @doubleliteral
| 21 = @characterliteral
| 22 = @stringliteral
| 23 = @nullliteral
| 24 = @mulexpr
| 25 = @divexpr
| 26 = @remexpr
| 27 = @addexpr
| 28 = @subexpr
| 29 = @lshiftexpr
| 30 = @rshiftexpr
| 31 = @urshiftexpr
| 32 = @andbitexpr
| 33 = @orbitexpr
| 34 = @xorbitexpr
| 35 = @andlogicalexpr
| 36 = @orlogicalexpr
| 37 = @ltexpr
| 38 = @gtexpr
| 39 = @leexpr
| 40 = @geexpr
| 41 = @eqexpr
| 42 = @neexpr
| 43 = @postincexpr
| 44 = @postdecexpr
| 45 = @preincexpr
| 46 = @predecexpr
| 47 = @minusexpr
| 48 = @plusexpr
| 49 = @bitnotexpr
| 50 = @lognotexpr
| 51 = @castexpr
| 52 = @newexpr
| 53 = @conditionalexpr
| 54 = @parexpr // deprecated
| 55 = @instanceofexpr
| 56 = @localvariabledeclexpr
| 57 = @typeliteral
| 58 = @thisaccess
| 59 = @superaccess
| 60 = @varaccess
| 61 = @methodaccess
| 62 = @unannotatedtypeaccess
| 63 = @arraytypeaccess
| 64 = @packageaccess
| 65 = @wildcardtypeaccess
| 66 = @declannotation
| 67 = @uniontypeaccess
| 68 = @lambdaexpr
| 69 = @memberref
| 70 = @annotatedtypeaccess
| 71 = @typeannotation
| 72 = @intersectiontypeaccess
| 73 = @switchexpr
;
@classinstancexpr = @newexpr | @lambdaexpr | @memberref
@annotation = @declannotation | @typeannotation
@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess
@assignment = @assignexpr
| @assignop;
@unaryassignment = @postincexpr
| @postdecexpr
| @preincexpr
| @predecexpr;
@assignop = @assignaddexpr
| @assignsubexpr
| @assignmulexpr
| @assigndivexpr
| @assignremexpr
| @assignandexpr
| @assignorexpr
| @assignxorexpr
| @assignlshiftexpr
| @assignrshiftexpr
| @assignurshiftexpr;
@literal = @booleanliteral
| @integerliteral
| @longliteral
| @floatingpointliteral
| @doubleliteral
| @characterliteral
| @stringliteral
| @nullliteral;
@binaryexpr = @mulexpr
| @divexpr
| @remexpr
| @addexpr
| @subexpr
| @lshiftexpr
| @rshiftexpr
| @urshiftexpr
| @andbitexpr
| @orbitexpr
| @xorbitexpr
| @andlogicalexpr
| @orlogicalexpr
| @ltexpr
| @gtexpr
| @leexpr
| @geexpr
| @eqexpr
| @neexpr;
@unaryexpr = @postincexpr
| @postdecexpr
| @preincexpr
| @predecexpr
| @minusexpr
| @plusexpr
| @bitnotexpr
| @lognotexpr;
@caller = @classinstancexpr
| @methodaccess
| @constructorinvocationstmt
| @superconstructorinvocationstmt;
callableBinding(
unique int callerid: @caller ref,
int callee: @callable ref
);
memberRefBinding(
unique int id: @expr ref,
int callable: @callable ref
);
@exprparent = @stmt | @expr | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable;
variableBinding(
unique int expr: @varaccess ref,
int variable: @variable ref
);
@variable = @localscopevariable | @field;
@localscopevariable = @localvar | @param;
localvars(
unique int id: @localvar,
string nodeName: string ref,
int typeid: @type ref,
int parentid: @localvariabledeclexpr ref
);
@namedexprorstmt = @breakstmt
| @continuestmt
| @labeledstmt
| @literal;
namestrings(
string name: string ref,
string value: string ref,
unique int parent: @namedexprorstmt ref
);
/*
* Modules
*/
#keyset[name]
modules(
unique int id: @module,
string name: string ref
);
isOpen(
int id: @module ref
);
#keyset[fileId]
cumodule(
int fileId: @file ref,
int moduleId: @module ref
);
@directive = @requires
| @exports
| @opens
| @uses
| @provides
#keyset[directive]
directives(
int id: @module ref,
int directive: @directive ref
);
requires(
unique int id: @requires,
int target: @module ref
);
isTransitive(
int id: @requires ref
);
isStatic(
int id: @requires ref
);
exports(
unique int id: @exports,
int target: @package ref
);
exportsTo(
int id: @exports ref,
int target: @module ref
);
opens(
unique int id: @opens,
int target: @package ref
);
opensTo(
int id: @opens ref,
int target: @module ref
);
uses(
unique int id: @uses,
string serviceInterface: string ref
);
provides(
unique int id: @provides,
string serviceInterface: string ref
);
providesWith(
int id: @provides ref,
string serviceImpl: string ref
);
/*
* Javadoc
*/
javadoc(
unique int id: @javadoc
);
isNormalComment(
int commentid : @javadoc ref
);
isEolComment(
int commentid : @javadoc ref
);
hasJavadoc(
int documentableid: @member ref,
int javadocid: @javadoc ref
);
#keyset[parentid,idx]
javadocTag(
unique int id: @javadocTag,
string name: string ref,
int parentid: @javadocParent ref,
int idx: int ref
);
#keyset[parentid,idx]
javadocText(
unique int id: @javadocText,
string text: string ref,
int parentid: @javadocParent ref,
int idx: int ref
);
@javadocParent = @javadoc | @javadocTag;
@javadocElement = @javadocTag | @javadocText;
@classorinterface = @interface | @class;
@classorinterfaceorpackage = @classorinterface | @package;
@classorinterfaceorcallable = @classorinterface | @callable;
@boundedtype = @typevariable | @wildcard;
@reftype = @classorinterface | @array | @boundedtype;
@classorarray = @class | @array;
@type = @primitive | @reftype;
@callable = @method | @constructor;
@element = @file | @package | @primitive | @class | @interface | @method | @constructor | @modifier | @param | @exception | @field |
@annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl;
@modifiable = @member_modifiable| @param | @localvar ;
@member_modifiable = @class | @interface | @method | @constructor | @field ;
@member = @method | @constructor | @field | @reftype ;
@locatable = @file | @class | @interface | @fielddecl | @field | @constructor | @method | @param | @exception
| @boundedtype | @typebound | @array | @primitive
| @import | @stmt | @expr | @localvar | @javadoc | @javadocTag | @javadocText
| @xmllocatable;
@top = @element | @locatable | @folder;
/*
* XML Files
*/
xmlEncoding(
unique int id: @file ref,
string encoding: string ref
);
xmlDTDs(
unique int id: @xmldtd,
string root: string ref,
string publicId: string ref,
string systemId: string ref,
int fileid: @file ref
);
xmlElements(
unique int id: @xmlelement,
string name: string ref,
int parentid: @xmlparent ref,
int idx: int ref,
int fileid: @file ref
);
xmlAttrs(
unique int id: @xmlattribute,
int elementid: @xmlelement ref,
string name: string ref,
string value: string ref,
int idx: int ref,
int fileid: @file ref
);
xmlNs(
int id: @xmlnamespace,
string prefixName: string ref,
string URI: string ref,
int fileid: @file ref
);
xmlHasNs(
int elementId: @xmlnamespaceable ref,
int nsId: @xmlnamespace ref,
int fileid: @file ref
);
xmlComments(
unique int id: @xmlcomment,
string text: string ref,
int parentid: @xmlparent ref,
int fileid: @file ref
);
xmlChars(
unique int id: @xmlcharacters,
string text: string ref,
int parentid: @xmlparent ref,
int idx: int ref,
int isCDATA: int ref,
int fileid: @file ref
);
@xmlparent = @file | @xmlelement;
@xmlnamespaceable = @xmlelement | @xmlattribute;
xmllocations(
int xmlElement: @xmllocatable ref,
int location: @location_default ref
);
@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
/*
* configuration files with key value pairs
*/
configs(
unique int id: @config
);
configNames(
unique int id: @configName,
int config: @config ref,
string name: string ref
);
configValues(
unique int id: @configValue,
int config: @config ref,
string value: string ref
);
configLocations(
int locatable: @configLocatable ref,
int location: @location_default ref
);
@configLocatable = @config | @configName | @configValue;

View File

@@ -0,0 +1,984 @@
/**
* An invocation of the compiler. Note that more than one file may be
* compiled per invocation. For example, this command compiles three
* source files:
*
* javac A.java B.java C.java
*
* The `id` simply identifies the invocation, while `cwd` is the working
* directory from which the compiler was invoked.
*/
compilations(
/**
* An invocation of the compiler. Note that more than one file may
* be compiled per invocation. For example, this command compiles
* three source files:
*
* javac A.java B.java C.java
*/
unique int id : @compilation,
string cwd : string ref
);
/**
* The arguments that were passed to the extractor for a compiler
* invocation. If `id` is for the compiler invocation
*
* javac A.java B.java C.java
*
* then typically there will be rows for
*
* num | arg
* --- | ---
* 0 | *path to extractor*
* 1 | `--javac-args`
* 2 | A.java
* 3 | B.java
* 4 | C.java
*/
#keyset[id, num]
compilation_args(
int id : @compilation ref,
int num : int ref,
string arg : string ref
);
/**
* The source files that are compiled by a compiler invocation.
* If `id` is for the compiler invocation
*
* javac A.java B.java C.java
*
* then there will be rows for
*
* num | arg
* --- | ---
* 0 | A.java
* 1 | B.java
* 2 | C.java
*/
#keyset[id, num]
compilation_compiling_files(
int id : @compilation ref,
int num : int ref,
int file : @file ref
);
/**
* The time taken by the extractor for a compiler invocation.
*
* For each file `num`, there will be rows for
*
* kind | seconds
* ---- | ---
* 1 | CPU seconds used by the extractor frontend
* 2 | Elapsed seconds during the extractor frontend
* 3 | CPU seconds used by the extractor backend
* 4 | Elapsed seconds during the extractor backend
*/
#keyset[id, num, kind]
compilation_time(
int id : @compilation ref,
int num : int ref,
/* kind:
1 = frontend_cpu_seconds
2 = frontend_elapsed_seconds
3 = extractor_cpu_seconds
4 = extractor_elapsed_seconds
*/
int kind : int ref,
float seconds : float ref
);
/**
* An error or warning generated by the extractor.
* The diagnostic message `diagnostic` was generated during compiler
* invocation `compilation`, and is the `file_number_diagnostic_number`th
* message generated while extracting the `file_number`th file of that
* invocation.
*/
#keyset[compilation, file_number, file_number_diagnostic_number]
diagnostic_for(
unique int diagnostic : @diagnostic ref,
int compilation : @compilation ref,
int file_number : int ref,
int file_number_diagnostic_number : int ref
);
/**
* If extraction was successful, then `cpu_seconds` and
* `elapsed_seconds` are the CPU time and elapsed time (respectively)
* that extraction took for compiler invocation `id`.
*/
compilation_finished(
unique int id : @compilation ref,
float cpu_seconds : float ref,
float elapsed_seconds : float ref
);
diagnostics(
unique int id: @diagnostic,
int severity: int ref,
string error_tag: string ref,
string error_message: string ref,
string full_error_message: string ref,
int location: @location_default ref
);
/*
* External artifacts
*/
externalData(
int id : @externalDataElement,
string path : string ref,
int column: int ref,
string value : string ref
);
snapshotDate(
unique date snapshotDate : date ref
);
sourceLocationPrefix(
string prefix : string ref
);
/*
* Duplicate code
*/
duplicateCode(
unique int id : @duplication,
string relativePath : string ref,
int equivClass : int ref
);
similarCode(
unique int id : @similarity,
string relativePath : string ref,
int equivClass : int ref
);
@duplication_or_similarity = @duplication | @similarity
tokens(
int id : @duplication_or_similarity ref,
int offset : int ref,
int beginLine : int ref,
int beginColumn : int ref,
int endLine : int ref,
int endColumn : int ref
);
/*
* SMAP
*/
smap_header(
int outputFileId: @file ref,
string outputFilename: string ref,
string defaultStratum: string ref
);
smap_files(
int outputFileId: @file ref,
string stratum: string ref,
int inputFileNum: int ref,
string inputFileName: string ref,
int inputFileId: @file ref
);
smap_lines(
int outputFileId: @file ref,
string stratum: string ref,
int inputFileNum: int ref,
int inputStartLine: int ref,
int inputLineCount: int ref,
int outputStartLine: int ref,
int outputLineIncrement: int ref
);
/*
* Locations and files
*/
@location = @location_default ;
locations_default(
unique int id: @location_default,
int file: @file ref,
int beginLine: int ref,
int beginColumn: int ref,
int endLine: int ref,
int endColumn: int ref
);
hasLocation(
int locatableid: @locatable ref,
int id: @location ref
);
@sourceline = @locatable ;
#keyset[element_id]
numlines(
int element_id: @sourceline ref,
int num_lines: int ref,
int num_code: int ref,
int num_comment: int ref
);
files(
unique int id: @file,
string name: string ref
);
folders(
unique int id: @folder,
string name: string ref
);
@container = @folder | @file
containerparent(
int parent: @container ref,
unique int child: @container ref
);
/*
* Java
*/
cupackage(
unique int id: @file ref,
int packageid: @package ref
);
#keyset[fileid,keyName]
jarManifestMain(
int fileid: @file ref,
string keyName: string ref,
string value: string ref
);
#keyset[fileid,entryName,keyName]
jarManifestEntries(
int fileid: @file ref,
string entryName: string ref,
string keyName: string ref,
string value: string ref
);
packages(
unique int id: @package,
string nodeName: string ref
);
primitives(
unique int id: @primitive,
string nodeName: string ref
);
modifiers(
unique int id: @modifier,
string nodeName: string ref
);
classes(
unique int id: @class,
string nodeName: string ref,
int parentid: @package ref,
int sourceid: @class ref
);
isRecord(
unique int id: @class ref
);
interfaces(
unique int id: @interface,
string nodeName: string ref,
int parentid: @package ref,
int sourceid: @interface ref
);
fielddecls(
unique int id: @fielddecl,
int parentid: @reftype ref
);
#keyset[fieldId] #keyset[fieldDeclId,pos]
fieldDeclaredIn(
int fieldId: @field ref,
int fieldDeclId: @fielddecl ref,
int pos: int ref
);
fields(
unique int id: @field,
string nodeName: string ref,
int typeid: @type ref,
int parentid: @reftype ref,
int sourceid: @field ref
);
constrs(
unique int id: @constructor,
string nodeName: string ref,
string signature: string ref,
int typeid: @type ref,
int parentid: @reftype ref,
int sourceid: @constructor ref
);
methods(
unique int id: @method,
string nodeName: string ref,
string signature: string ref,
int typeid: @type ref,
int parentid: @reftype ref,
int sourceid: @method ref
);
#keyset[parentid,pos]
params(
unique int id: @param,
int typeid: @type ref,
int pos: int ref,
int parentid: @callable ref,
int sourceid: @param ref
);
paramName(
unique int id: @param ref,
string nodeName: string ref
);
isVarargsParam(
int param: @param ref
);
exceptions(
unique int id: @exception,
int typeid: @type ref,
int parentid: @callable ref
);
isAnnotType(
int interfaceid: @interface ref
);
isAnnotElem(
int methodid: @method ref
);
annotValue(
int parentid: @annotation ref,
int id2: @method ref,
unique int value: @expr ref
);
isEnumType(
int classid: @class ref
);
isEnumConst(
int fieldid: @field ref
);
#keyset[parentid,pos]
typeVars(
unique int id: @typevariable,
string nodeName: string ref,
int pos: int ref,
int kind: int ref, // deprecated
int parentid: @classorinterfaceorcallable ref
);
wildcards(
unique int id: @wildcard,
string nodeName: string ref,
int kind: int ref
);
#keyset[parentid,pos]
typeBounds(
unique int id: @typebound,
int typeid: @reftype ref,
int pos: int ref,
int parentid: @boundedtype ref
);
#keyset[parentid,pos]
typeArgs(
int argumentid: @reftype ref,
int pos: int ref,
int parentid: @classorinterfaceorcallable ref
);
isParameterized(
int memberid: @member ref
);
isRaw(
int memberid: @member ref
);
erasure(
unique int memberid: @member ref,
int erasureid: @member ref
);
#keyset[classid] #keyset[parent]
isAnonymClass(
int classid: @class ref,
int parent: @classinstancexpr ref
);
#keyset[typeid] #keyset[parent]
isLocalClassOrInterface(
int typeid: @classorinterface ref,
int parent: @localtypedeclstmt ref
);
isDefConstr(
int constructorid: @constructor ref
);
#keyset[exprId]
lambdaKind(
int exprId: @lambdaexpr ref,
int bodyKind: int ref
);
arrays(
unique int id: @array,
string nodeName: string ref,
int elementtypeid: @type ref,
int dimension: int ref,
int componenttypeid: @type ref
);
enclInReftype(
unique int child: @reftype ref,
int parent: @reftype ref
);
extendsReftype(
int id1: @reftype ref,
int id2: @classorinterface ref
);
implInterface(
int id1: @classorarray ref,
int id2: @interface ref
);
permits(
int id1: @classorinterface ref,
int id2: @classorinterface ref
);
hasModifier(
int id1: @modifiable ref,
int id2: @modifier ref
);
imports(
unique int id: @import,
int holder: @classorinterfaceorpackage ref,
string name: string ref,
int kind: int ref
);
#keyset[parent,idx]
stmts(
unique int id: @stmt,
int kind: int ref,
int parent: @stmtparent ref,
int idx: int ref,
int bodydecl: @callable ref
);
@stmtparent = @callable | @stmt | @switchexpr;
case @stmt.kind of
0 = @block
| 1 = @ifstmt
| 2 = @forstmt
| 3 = @enhancedforstmt
| 4 = @whilestmt
| 5 = @dostmt
| 6 = @trystmt
| 7 = @switchstmt
| 8 = @synchronizedstmt
| 9 = @returnstmt
| 10 = @throwstmt
| 11 = @breakstmt
| 12 = @continuestmt
| 13 = @emptystmt
| 14 = @exprstmt
| 15 = @labeledstmt
| 16 = @assertstmt
| 17 = @localvariabledeclstmt
| 18 = @localtypedeclstmt
| 19 = @constructorinvocationstmt
| 20 = @superconstructorinvocationstmt
| 21 = @case
| 22 = @catchclause
| 23 = @yieldstmt
| 24 = @errorstmt
;
#keyset[parent,idx]
exprs(
unique int id: @expr,
int kind: int ref,
int typeid: @type ref,
int parent: @exprparent ref,
int idx: int ref
);
callableEnclosingExpr(
unique int id: @expr ref,
int callable_id: @callable ref
);
statementEnclosingExpr(
unique int id: @expr ref,
int statement_id: @stmt ref
);
isParenthesized(
unique int id: @expr ref,
int parentheses: int ref
);
case @expr.kind of
1 = @arrayaccess
| 2 = @arraycreationexpr
| 3 = @arrayinit
| 4 = @assignexpr
| 5 = @assignaddexpr
| 6 = @assignsubexpr
| 7 = @assignmulexpr
| 8 = @assigndivexpr
| 9 = @assignremexpr
| 10 = @assignandexpr
| 11 = @assignorexpr
| 12 = @assignxorexpr
| 13 = @assignlshiftexpr
| 14 = @assignrshiftexpr
| 15 = @assignurshiftexpr
| 16 = @booleanliteral
| 17 = @integerliteral
| 18 = @longliteral
| 19 = @floatingpointliteral
| 20 = @doubleliteral
| 21 = @characterliteral
| 22 = @stringliteral
| 23 = @nullliteral
| 24 = @mulexpr
| 25 = @divexpr
| 26 = @remexpr
| 27 = @addexpr
| 28 = @subexpr
| 29 = @lshiftexpr
| 30 = @rshiftexpr
| 31 = @urshiftexpr
| 32 = @andbitexpr
| 33 = @orbitexpr
| 34 = @xorbitexpr
| 35 = @andlogicalexpr
| 36 = @orlogicalexpr
| 37 = @ltexpr
| 38 = @gtexpr
| 39 = @leexpr
| 40 = @geexpr
| 41 = @eqexpr
| 42 = @neexpr
| 43 = @postincexpr
| 44 = @postdecexpr
| 45 = @preincexpr
| 46 = @predecexpr
| 47 = @minusexpr
| 48 = @plusexpr
| 49 = @bitnotexpr
| 50 = @lognotexpr
| 51 = @castexpr
| 52 = @newexpr
| 53 = @conditionalexpr
| 54 = @parexpr // deprecated
| 55 = @instanceofexpr
| 56 = @localvariabledeclexpr
| 57 = @typeliteral
| 58 = @thisaccess
| 59 = @superaccess
| 60 = @varaccess
| 61 = @methodaccess
| 62 = @unannotatedtypeaccess
| 63 = @arraytypeaccess
| 64 = @packageaccess
| 65 = @wildcardtypeaccess
| 66 = @declannotation
| 67 = @uniontypeaccess
| 68 = @lambdaexpr
| 69 = @memberref
| 70 = @annotatedtypeaccess
| 71 = @typeannotation
| 72 = @intersectiontypeaccess
| 73 = @switchexpr
| 74 = @errorexpr
;
@classinstancexpr = @newexpr | @lambdaexpr | @memberref
@annotation = @declannotation | @typeannotation
@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess
@assignment = @assignexpr
| @assignop;
@unaryassignment = @postincexpr
| @postdecexpr
| @preincexpr
| @predecexpr;
@assignop = @assignaddexpr
| @assignsubexpr
| @assignmulexpr
| @assigndivexpr
| @assignremexpr
| @assignandexpr
| @assignorexpr
| @assignxorexpr
| @assignlshiftexpr
| @assignrshiftexpr
| @assignurshiftexpr;
@literal = @booleanliteral
| @integerliteral
| @longliteral
| @floatingpointliteral
| @doubleliteral
| @characterliteral
| @stringliteral
| @nullliteral;
@binaryexpr = @mulexpr
| @divexpr
| @remexpr
| @addexpr
| @subexpr
| @lshiftexpr
| @rshiftexpr
| @urshiftexpr
| @andbitexpr
| @orbitexpr
| @xorbitexpr
| @andlogicalexpr
| @orlogicalexpr
| @ltexpr
| @gtexpr
| @leexpr
| @geexpr
| @eqexpr
| @neexpr;
@unaryexpr = @postincexpr
| @postdecexpr
| @preincexpr
| @predecexpr
| @minusexpr
| @plusexpr
| @bitnotexpr
| @lognotexpr;
@caller = @classinstancexpr
| @methodaccess
| @constructorinvocationstmt
| @superconstructorinvocationstmt;
callableBinding(
unique int callerid: @caller ref,
int callee: @callable ref
);
memberRefBinding(
unique int id: @expr ref,
int callable: @callable ref
);
@exprparent = @stmt | @expr | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable;
variableBinding(
unique int expr: @varaccess ref,
int variable: @variable ref
);
@variable = @localscopevariable | @field;
@localscopevariable = @localvar | @param;
localvars(
unique int id: @localvar,
string nodeName: string ref,
int typeid: @type ref,
int parentid: @localvariabledeclexpr ref
);
@namedexprorstmt = @breakstmt
| @continuestmt
| @labeledstmt
| @literal;
namestrings(
string name: string ref,
string value: string ref,
unique int parent: @namedexprorstmt ref
);
/*
* Modules
*/
#keyset[name]
modules(
unique int id: @module,
string name: string ref
);
isOpen(
int id: @module ref
);
#keyset[fileId]
cumodule(
int fileId: @file ref,
int moduleId: @module ref
);
@directive = @requires
| @exports
| @opens
| @uses
| @provides
#keyset[directive]
directives(
int id: @module ref,
int directive: @directive ref
);
requires(
unique int id: @requires,
int target: @module ref
);
isTransitive(
int id: @requires ref
);
isStatic(
int id: @requires ref
);
exports(
unique int id: @exports,
int target: @package ref
);
exportsTo(
int id: @exports ref,
int target: @module ref
);
opens(
unique int id: @opens,
int target: @package ref
);
opensTo(
int id: @opens ref,
int target: @module ref
);
uses(
unique int id: @uses,
string serviceInterface: string ref
);
provides(
unique int id: @provides,
string serviceInterface: string ref
);
providesWith(
int id: @provides ref,
string serviceImpl: string ref
);
/*
* Javadoc
*/
javadoc(
unique int id: @javadoc
);
isNormalComment(
int commentid : @javadoc ref
);
isEolComment(
int commentid : @javadoc ref
);
hasJavadoc(
int documentableid: @member ref,
int javadocid: @javadoc ref
);
#keyset[parentid,idx]
javadocTag(
unique int id: @javadocTag,
string name: string ref,
int parentid: @javadocParent ref,
int idx: int ref
);
#keyset[parentid,idx]
javadocText(
unique int id: @javadocText,
string text: string ref,
int parentid: @javadocParent ref,
int idx: int ref
);
@javadocParent = @javadoc | @javadocTag;
@javadocElement = @javadocTag | @javadocText;
@classorinterface = @interface | @class;
@classorinterfaceorpackage = @classorinterface | @package;
@classorinterfaceorcallable = @classorinterface | @callable;
@boundedtype = @typevariable | @wildcard;
@reftype = @classorinterface | @array | @boundedtype;
@classorarray = @class | @array;
@type = @primitive | @reftype;
@callable = @method | @constructor;
@element = @file | @package | @primitive | @class | @interface | @method | @constructor | @modifier | @param | @exception | @field |
@annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl;
@modifiable = @member_modifiable| @param | @localvar ;
@member_modifiable = @class | @interface | @method | @constructor | @field ;
@member = @method | @constructor | @field | @reftype ;
@locatable = @file | @class | @interface | @fielddecl | @field | @constructor | @method | @param | @exception
| @boundedtype | @typebound | @array | @primitive
| @import | @stmt | @expr | @localvar | @javadoc | @javadocTag | @javadocText
| @xmllocatable;
@top = @element | @locatable | @folder;
/*
* XML Files
*/
xmlEncoding(
unique int id: @file ref,
string encoding: string ref
);
xmlDTDs(
unique int id: @xmldtd,
string root: string ref,
string publicId: string ref,
string systemId: string ref,
int fileid: @file ref
);
xmlElements(
unique int id: @xmlelement,
string name: string ref,
int parentid: @xmlparent ref,
int idx: int ref,
int fileid: @file ref
);
xmlAttrs(
unique int id: @xmlattribute,
int elementid: @xmlelement ref,
string name: string ref,
string value: string ref,
int idx: int ref,
int fileid: @file ref
);
xmlNs(
int id: @xmlnamespace,
string prefixName: string ref,
string URI: string ref,
int fileid: @file ref
);
xmlHasNs(
int elementId: @xmlnamespaceable ref,
int nsId: @xmlnamespace ref,
int fileid: @file ref
);
xmlComments(
unique int id: @xmlcomment,
string text: string ref,
int parentid: @xmlparent ref,
int fileid: @file ref
);
xmlChars(
unique int id: @xmlcharacters,
string text: string ref,
int parentid: @xmlparent ref,
int idx: int ref,
int isCDATA: int ref,
int fileid: @file ref
);
@xmlparent = @file | @xmlelement;
@xmlnamespaceable = @xmlelement | @xmlattribute;
xmllocations(
int xmlElement: @xmllocatable ref,
int location: @location_default ref
);
@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
/*
* configuration files with key value pairs
*/
configs(
unique int id: @config
);
configNames(
unique int id: @configName,
int config: @config ref,
string name: string ref
);
configValues(
unique int id: @configValue,
int config: @config ref,
string value: string ref
);
configLocations(
int locatable: @configLocatable ref,
int location: @location_default ref
);
@configLocatable = @config | @configName | @configValue;

View File

@@ -0,0 +1,3 @@
description: Add @errorstmt, @errorexpr
compatibility: backwards

View File

@@ -1,178 +1,15 @@
#!/usr/bin/python3
import json
import os
import os.path
import shlex
import subprocess
import sys
import tempfile
import os.path
import subprocess
# Add Model as Data script directory to sys.path.
gitroot = subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode("utf-8").strip()
madpath = os.path.join(gitroot, "misc/scripts/models-as-data/")
sys.path.append(madpath)
def printHelp():
print("""Usage:
GenerateFlowModel.py <library-database> <outputQll> [--with-sinks] [--with-sources] [--with-summaries]
import generate_flow_model as model
This generates summary, source and sink models for the code in the database.
The files will be placed in `java/ql/lib/semmle/code/java/frameworks/<outputQll>` where
outputQll is the name (and path) of the output QLL file. Usually, models are grouped by their
respective frameworks.
Which models are generated is controlled by the flags:
--with-sinks
--with-sources
--with-summaries
If none of these flags are specified, all models are generated.
Example invocations:
$ GenerateFlowModel.py /tmp/dbs/apache_commons-codec_45649c8 "apache/Codec.qll"
$ GenerateFlowModel.py /tmp/dbs/jdk15_db "javase/jdk_sinks.qll" --with-sinks
Requirements: `codeql` should both appear on your path.
""")
if any(s == "--help" for s in sys.argv):
printHelp()
sys.exit(0)
generateSinks = False
generateSources = False
generateSummaries = False
if "--with-sinks" in sys.argv:
sys.argv.remove("--with-sinks")
generateSinks = True
if "--with-sources" in sys.argv:
sys.argv.remove("--with-sources")
generateSources = True
if "--with-summaries" in sys.argv:
sys.argv.remove("--with-summaries")
generateSummaries = True
if not generateSinks and not generateSources and not generateSummaries:
generateSinks = generateSources = generateSummaries = True
if len(sys.argv) != 3:
printHelp()
sys.exit(1)
codeQlRoot = subprocess.check_output(
["git", "rev-parse", "--show-toplevel"]).decode("utf-8").strip()
targetQll = sys.argv[2]
if not targetQll.endswith(".qll"):
targetQll += ".qll"
filename = os.path.basename(targetQll)
shortname = filename[:-4]
generatedFrameworks = os.path.join(
codeQlRoot, "java/ql/lib/semmle/code/java/frameworks/")
frameworkTarget = os.path.join(generatedFrameworks, targetQll)
workDir = tempfile.mkdtemp()
os.makedirs(generatedFrameworks, exist_ok=True)
def runQuery(infoMessage, query):
print("########## Querying " + infoMessage + "...")
database = sys.argv[1]
queryFile = os.path.join(os.path.dirname(
__file__), query)
resultBqrs = os.path.join(workDir, "out.bqrs")
cmd = ['codeql', 'query', 'run', queryFile, '--database',
database, '--output', resultBqrs, '--threads', '8']
ret = subprocess.call(cmd)
if ret != 0:
print("Failed to generate " + infoMessage +
". Failed command was: " + shlex.join(cmd))
sys.exit(1)
return readRows(resultBqrs)
def readRows(bqrsFile):
generatedJson = os.path.join(workDir, "out.json")
cmd = ['codeql', 'bqrs', 'decode', bqrsFile,
'--format=json', '--output', generatedJson]
ret = subprocess.call(cmd)
if ret != 0:
print("Failed to decode BQRS. Failed command was: " + shlex.join(cmd))
sys.exit(1)
with open(generatedJson) as f:
results = json.load(f)
try:
results['#select']['tuples']
except KeyError:
print('Unexpected JSON output - no tuples found')
exit(1)
rows = ""
for (row) in results['#select']['tuples']:
rows += " \"" + row[0] + "\",\n"
return rows[:-2]
def asCsvModel(superclass, kind, rows):
classTemplate = """
private class {0}{1}Csv extends {2} {{
override predicate row(string row) {{
row =
[
{3}
]
}}
}}
"""
if rows.strip() == "":
return ""
return classTemplate.format(shortname[0].upper() + shortname[1:], kind.capitalize(), superclass, rows)
if generateSummaries:
summaryRows = runQuery("summary models", "CaptureSummaryModels.ql")
summaryCsv = asCsvModel("SummaryModelCsv", "summary", summaryRows)
else:
summaryCsv = ""
if generateSinks:
sinkRows = runQuery("sink models", "CaptureSinkModels.ql")
sinkCsv = asCsvModel("SinkModelCsv", "sinks", sinkRows)
else:
sinkCsv = ""
if generateSources:
sourceRows = runQuery("source models", "CaptureSourceModels.ql")
sourceCsv = asCsvModel("SourceModelCsv", "sources", sourceRows)
else:
sourceCsv = ""
qllTemplate = """
/** Definitions of taint steps in the {0} framework */
import java
private import semmle.code.java.dataflow.ExternalFlow
{1}
{2}
{3}
"""
qllContents = qllTemplate.format(shortname, sinkCsv, sourceCsv, summaryCsv)
with open(frameworkTarget, "w") as frameworkQll:
frameworkQll.write(qllContents)
cmd = ['codeql', 'query', 'format', '--in-place', frameworkTarget]
ret = subprocess.call(cmd)
if ret != 0:
print("Failed to format query. Failed command was: " + shlex.join(cmd))
sys.exit(1)
print("")
print("CSV model written to " + frameworkTarget)
language = "java"
model.Generator.make(language).run()

View File

@@ -192,8 +192,8 @@ class Test {
sink(StringUtils.rotate(taint(), 0)); // $hasTaintFlow
sink(StringUtils.split(taint())); // $hasTaintFlow
sink(StringUtils.split(taint(), ' ')); // $hasTaintFlow
sink(StringUtils.split(taint(), " ,; // $hasTaintFlow")); // $hasTaintFlow
sink(StringUtils.split(taint(), " ,; // $hasTaintFlow", 0)); // $hasTaintFlow
sink(StringUtils.split(taint(), " ,;")); // $hasTaintFlow
sink(StringUtils.split(taint(), " ,;", 0)); // $hasTaintFlow
sink(StringUtils.splitByCharacterType(taint())); // $hasTaintFlow
sink(StringUtils.splitByCharacterTypeCamelCase(taint())); // $hasTaintFlow
sink(StringUtils.splitByWholeSeparator(taint(), "separator")); // $hasTaintFlow

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-experimental-atm-lib
version: 0.1.1
version: 0.2.1
extractor: javascript
library: true
groups:

View File

@@ -1,7 +1,7 @@
name: codeql/javascript-experimental-atm-model
version: 0.0.6
version: 0.1.1
groups:
- javascript
- experimental
mlModels:
- "resources/*.codeqlmodel"
- "resources/*.codeqlmodel"

View File

@@ -1,6 +1,6 @@
---
dependencies:
codeql/javascript-experimental-atm-model:
version: 0.0.6
version: 0.1.0
compiled: false
lockVersion: 1.0.0

View File

@@ -75,7 +75,11 @@ private DataFlow::Node getANotASink(NotASinkReason reason) {
*/
private DataFlow::Node getAnUnknown(Query query) {
getAtmCfg(query).isEffectiveSink(result) and
// Effective sinks should exclude sinks but this is a defensive requirement
not result = getASink(query) and
// Effective sinks should exclude NotASink but for some queries (e.g. Xss) this is currently not always the case and
// so this is a defensive requirement
not result = getANotASink(_) and
// Only consider the source code for the project being analyzed.
exists(result.getFile().getRelativePath())
}

View File

@@ -6,4 +6,4 @@ groups:
- experimental
dependencies:
codeql/javascript-experimental-atm-lib: "*"
codeql/javascript-experimental-atm-model: "0.0.6"
codeql/javascript-experimental-atm-model: "0.1.0"

View File

@@ -1,6 +1,6 @@
---
dependencies:
codeql/javascript-experimental-atm-model:
version: 0.0.6
version: 0.1.0
compiled: false
lockVersion: 1.0.0

View File

@@ -1,6 +1,6 @@
name: codeql/javascript-experimental-atm-queries
language: javascript
version: 0.1.1
version: 0.2.1
suites: codeql-suites
defaultSuiteFile: codeql-suites/javascript-atm-code-scanning.qls
groups:
@@ -8,4 +8,4 @@ groups:
- experimental
dependencies:
codeql/javascript-experimental-atm-lib: "*"
codeql/javascript-experimental-atm-model: "0.0.6"
codeql/javascript-experimental-atm-model: "0.1.0"

View File

@@ -1,6 +1,6 @@
---
dependencies:
codeql/javascript-experimental-atm-model:
version: 0.0.6
version: 0.1.0
compiled: false
lockVersion: 1.0.0

View File

@@ -8434,24 +8434,24 @@ tokenFeatures
| autogenerated/Xss/DomBasedXss/d3.js:14:15:14:29 | d => getTaint() | enclosingFunctionBody | d3 select #main attr width 100 style color red html getTaint html d getTaint call otherFunction html d getTaint |
| autogenerated/Xss/DomBasedXss/d3.js:14:15:14:29 | d => getTaint() | enclosingFunctionName | doSomething |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | argumentIndex | 0 |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPath | d3 select attr style html html call selection attr d3 select attr style html html selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPath | d3 select attr style html html call selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeName | attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | enclosingFunctionBody | selection selection attr foo bar html getTaint |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | enclosingFunctionName | otherFunction |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | receiverName | selection |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | argumentIndex | 1 |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPath | d3 select attr style html html call selection attr d3 select attr style html html selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPath | d3 select attr style html html call selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeName | attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | enclosingFunctionBody | selection selection attr foo bar html getTaint |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | enclosingFunctionName | otherFunction |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | receiverName | selection |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | argumentIndex | 0 |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPath | d3 select attr style html html call selection attr html d3 select attr style html html selection attr html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn member html instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn member html instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPath | d3 select attr style html html call selection attr html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn member html instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeName | html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | enclosingFunctionBody | selection selection attr foo bar html getTaint |

View File

@@ -37241,24 +37241,24 @@ tokenFeatures
| autogenerated/Xss/DomBasedXss/d3.js:14:20:14:29 | getTaint() | enclosingFunctionName | doSomething |
| autogenerated/Xss/DomBasedXss/d3.js:14:20:14:29 | getTaint() | receiverName | |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | argumentIndex | 0 |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPath | d3 select attr style html html call selection attr d3 select attr style html html selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPath | d3 select attr style html html call selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeName | attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | enclosingFunctionBody | selection selection attr foo bar html getTaint |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | enclosingFunctionName | otherFunction |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | receiverName | selection |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | argumentIndex | 1 |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPath | d3 select attr style html html call selection attr d3 select attr style html html selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPath | d3 select attr style html html call selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeName | attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | enclosingFunctionBody | selection selection attr foo bar html getTaint |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | enclosingFunctionName | otherFunction |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | receiverName | selection |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | argumentIndex | 0 |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPath | d3 select attr style html html call selection attr html d3 select attr style html html selection attr html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn member html instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn member html instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPath | d3 select attr style html html call selection attr html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn member html instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeName | html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | enclosingFunctionBody | selection selection attr foo bar html getTaint |

View File

@@ -37241,24 +37241,24 @@ tokenFeatures
| autogenerated/Xss/DomBasedXss/d3.js:14:20:14:29 | getTaint() | enclosingFunctionName | doSomething |
| autogenerated/Xss/DomBasedXss/d3.js:14:20:14:29 | getTaint() | receiverName | |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | argumentIndex | 0 |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPath | d3 select attr style html html call selection attr d3 select attr style html html selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPath | d3 select attr style html html call selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | calleeName | attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | enclosingFunctionBody | selection selection attr foo bar html getTaint |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | enclosingFunctionName | otherFunction |
| autogenerated/Xss/DomBasedXss/d3.js:20:15:20:19 | 'foo' | receiverName | selection |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | argumentIndex | 1 |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPath | d3 select attr style html html call selection attr d3 select attr style html html selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPath | d3 select attr style html html call selection attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | calleeName | attr |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | enclosingFunctionBody | selection selection attr foo bar html getTaint |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | enclosingFunctionName | otherFunction |
| autogenerated/Xss/DomBasedXss/d3.js:20:22:20:26 | 'bar' | receiverName | selection |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | argumentIndex | 0 |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPath | d3 select attr style html html call selection attr html d3 select attr style html html selection attr html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn member html instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn member html instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPath | d3 select attr style html html call selection attr html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn member html instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeName | html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | enclosingFunctionBody | selection selection attr foo bar html getTaint |

View File

@@ -9393,8 +9393,8 @@ tokenFeatures
| autogenerated/Xss/DomBasedXss/d3.js:14:20:14:29 | getTaint() | enclosingFunctionName | doSomething |
| autogenerated/Xss/DomBasedXss/d3.js:14:20:14:29 | getTaint() | receiverName | |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | argumentIndex | 0 |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPath | d3 select attr style html html call selection attr html d3 select attr style html html selection attr html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn functionalarg param selection member attr instanceorreturn member html instanceorreturn d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn member html instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPath | d3 select attr style html html call selection attr html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeAccessPathWithStructuralInfo | d3 member select instanceorreturn member attr instanceorreturn member style instanceorreturn member html instanceorreturn member html instanceorreturn member call functionalarg param selection member attr instanceorreturn member html instanceorreturn |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeApiName | d3 |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | calleeName | html |
| autogenerated/Xss/DomBasedXss/d3.js:21:15:21:24 | getTaint() | enclosingFunctionBody | selection selection attr foo bar html getTaint |

View File

@@ -0,0 +1,7 @@
---
category: fix
---
* The following predicates on `API::Node` have been changed so as not to include the receiver. The receiver should now only be accessed via `getReceiver()`.
- `getParameter(int i)` previously included the receiver when `i = -1`
- `getAParameter()` previously included the receiver
- `getLastParameter()` previously included the receiver for calls with no arguments

View File

@@ -187,8 +187,7 @@ module API {
}
/**
* Gets a node representing a parameter or the receiver of the function represented by this
* node.
* Gets a node representing a parameter of the function represented by this node.
*
* This predicate may result in a mix of parameters from different call sites in cases where
* there are multiple invocations of this API component.
@@ -198,8 +197,6 @@ module API {
Node getAParameter() {
Stages::ApiStage::ref() and
result = this.getParameter(_)
or
result = this.getReceiver()
}
/**
@@ -561,9 +558,10 @@ module API {
rhs = f.getExceptionalReturn()
)
or
exists(int i |
lbl = Label::parameter(i) and
argumentPassing(base, i, rhs)
exists(int i | argumentPassing(base, i, rhs) |
lbl = Label::parameter(i)
or
i = -1 and lbl = Label::receiver()
)
or
exists(DataFlow::SourceNode src, DataFlow::PropWrite pw |
@@ -1096,8 +1094,8 @@ module API {
*/
LabelParameter parameter(int i) { result.getIndex() = i }
/** Gets the `parameter` edge label for the receiver. */
LabelParameter receiver() { result = parameter(-1) }
/** Gets the edge label for the receiver. */
LabelReceiver receiver() { any() }
/** Gets the `return` edge label. */
LabelReturn return() { any() }
@@ -1132,12 +1130,13 @@ module API {
MkLabelUnknownMember() or
MkLabelParameter(int i) {
i =
[-1 .. max(int args |
[0 .. max(int args |
args = any(InvokeExpr invk).getNumArgument() or
args = any(Function f).getNumParameter()
)] or
i = [0 .. 10]
} or
MkLabelReceiver() or
MkLabelReturn() or
MkLabelPromised() or
MkLabelPromisedError() or
@@ -1225,6 +1224,11 @@ module API {
/** Gets the index of the parameter for this label. */
int getIndex() { result = i }
}
/** A label for the receiver of call, that is, the value passed as `this`. */
class LabelReceiver extends ApiLabel, MkLabelReceiver {
override string toString() { result = "receiver" }
}
}
}
}

View File

@@ -354,6 +354,35 @@ module DOM {
call.getNumArgument() = 1 and
unique(InferredType t | t = getArgumentTypeFromJQueryMethodGet(call)) = TTNumber()
)
or
// A `this` node from a callback given to a `$().each(callback)` call.
// purposely not using JQuery::MethodCall to avoid `jquery.each()`.
exists(DataFlow::CallNode eachCall | eachCall = JQuery::objectRef().getAMethodCall("each") |
this = DataFlow::thisNode(eachCall.getCallback(0).getFunction()) or
this = eachCall.getABoundCallbackParameter(0, 1)
)
or
// A read of an array-element from a JQuery object. E.g. `$("#foo")[0]`
exists(DataFlow::PropRead read |
read = this and read = JQuery::objectRef().getAPropertyRead()
|
unique(InferredType t | t = read.getPropertyNameExpr().analyze().getAType()) = TTNumber()
)
or
// A receiver node of an event handler on a DOM node
exists(DataFlow::SourceNode domNode, DataFlow::FunctionNode eventHandler |
// NOTE: we do not use `getABoundFunctionValue()`, since bound functions tend to have
// a different receiver anyway
eventHandler = domNode.getAPropertySource(any(string n | n.matches("on%")))
or
eventHandler =
domNode.getAMethodCall("addEventListener").getArgument(1).getAFunctionValue()
|
domNode = domValueRef() and
this = eventHandler.getReceiver()
)
or
this = DataFlow::thisNode(any(EventHandlerCode evt))
}
}
}
@@ -387,6 +416,11 @@ module DOM {
or
t.start() and
result = domValueRef().getAMethodCall(["item", "namedItem"])
or
t.startInProp("target") and
result = domEventSource()
or
exists(DataFlow::TypeTracker t2 | result = domValueRef(t2).track(t2, t))
}
/** Gets a data flow node that may refer to a value from the DOM. */

View File

@@ -183,12 +183,12 @@ module Promises {
/**
* Gets the pseudo-field used to describe resolved values in a promise.
*/
string valueProp() { none() }
string valueProp() { result = "$PromiseResolveField$" }
/**
* Gets the pseudo-field used to describe rejected values in a promise.
*/
string errorProp() { none() }
string errorProp() { result = "$PromiseRejectField$" }
}
/**

View File

@@ -756,10 +756,10 @@ private class AdditionalFlowStepAsSharedStep extends SharedFlowStep {
*/
module PseudoProperties {
bindingset[s]
private string pseudoProperty(string s) { none() }
private string pseudoProperty(string s) { result = "$" + s + "$" }
bindingset[s, v]
private string pseudoProperty(string s, string v) { none() }
private string pseudoProperty(string s, string v) { result = "$" + s + "|" + v + "$" }
/**
* Gets a pseudo-property for the location of elements in a `Set`

View File

@@ -136,7 +136,7 @@ module Angular2 {
/** Gets a reference to a `DomSanitizer` object. */
DataFlow::SourceNode domSanitizer() {
result.hasUnderlyingType("@angular/platform-browser", "DomSanitizer")
result.hasUnderlyingType(["@angular/platform-browser", "@angular/core"], "DomSanitizer")
}
/** A value that is about to be promoted to a trusted HTML or CSS value. */

View File

@@ -927,6 +927,28 @@ module Express {
override string getCredentialsKind() { result = kind }
}
/** A call to `response.sendFile`, considered as a file system access. */
private class ResponseSendFileAsFileSystemAccess extends FileSystemReadAccess,
DataFlow::MethodCallNode {
ResponseSendFileAsFileSystemAccess() {
exists(string name | name = "sendFile" or name = "sendfile" |
this.calls(any(ResponseExpr res).flow(), name)
)
}
override DataFlow::Node getADataNode() { none() }
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getRootPathArgument() {
result = this.(DataFlow::CallNode).getOptionArgument(1, "root")
}
override predicate isUpwardNavigationRejected(DataFlow::Node argument) {
argument = this.getAPathArgument()
}
}
/**
* A function that flows to a route setup.
*/

View File

@@ -4,6 +4,23 @@
import javascript
/**
* A call that can produce a file name.
*/
abstract private class FileNameProducer extends DataFlow::Node {
/**
* Gets a file name produced by this producer.
*/
abstract DataFlow::Node getAFileName();
}
/**
* A node that contains a file name, and is produced by a `ProducesFileNames`.
*/
private class ProducedFileName extends FileNameSource {
ProducedFileName() { this = any(FileNameProducer producer).getAFileName() }
}
/**
* A file name from the `walk-sync` library.
*/
@@ -101,3 +118,319 @@ private API::Node fastGlobFileName() {
private class FastGlobFileNameSource extends FileNameSource {
FastGlobFileNameSource() { this = fastGlobFileName().getAnImmediateUse() }
}
/**
* Classes and predicates for modeling the `fstream` library (https://www.npmjs.com/package/fstream).
*/
private module FStream {
/**
* Gets a reference to a method in the `fstream` library.
*/
private DataFlow::SourceNode getAnFStreamProperty(boolean writer) {
exists(DataFlow::SourceNode mod, string readOrWrite, string subMod |
mod = DataFlow::moduleImport("fstream") and
(
readOrWrite = "Reader" and writer = false
or
readOrWrite = "Writer" and writer = true
) and
subMod = ["File", "Dir", "Link", "Proxy"]
|
result = mod.getAPropertyRead(readOrWrite) or
result = mod.getAPropertyRead(readOrWrite).getAPropertyRead(subMod) or
result = mod.getAPropertyRead(subMod).getAPropertyRead(readOrWrite)
)
}
/**
* An invocation of a method defined in the `fstream` library.
*/
private class FStream extends FileSystemAccess, DataFlow::InvokeNode {
boolean writer;
FStream() { this = getAnFStreamProperty(writer).getAnInvocation() }
override DataFlow::Node getAPathArgument() {
result = this.getOptionArgument(0, "path")
or
not exists(this.getOptionArgument(0, "path")) and
result = this.getArgument(0)
}
}
/**
* An invocation of an `fstream` method that writes to a file.
*/
private class FStreamWriter extends FileSystemWriteAccess, FStream {
FStreamWriter() { writer = true }
override DataFlow::Node getADataNode() { none() }
}
/**
* An invocation of an `fstream` method that reads a file.
*/
private class FStreamReader extends FileSystemReadAccess, FStream {
FStreamReader() { writer = false }
override DataFlow::Node getADataNode() { none() }
}
}
/**
* A call to the library `write-file-atomic`.
*/
private class WriteFileAtomic extends FileSystemWriteAccess, DataFlow::CallNode {
WriteFileAtomic() {
this = DataFlow::moduleImport("write-file-atomic").getACall()
or
this = DataFlow::moduleMember("write-file-atomic", "sync").getACall()
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getADataNode() { result = this.getArgument(1) }
}
/**
* A call to the library `recursive-readdir`.
*/
private class RecursiveReadDir extends FileSystemAccess, FileNameProducer, API::CallNode {
RecursiveReadDir() { this = API::moduleImport("recursive-readdir").getACall() }
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getAFileName() { result = this.trackFileSource().getAnImmediateUse() }
private API::Node trackFileSource() {
result = this.getParameter([1 .. 2]).getParameter(1)
or
not exists(this.getCallback([1 .. 2])) and result = this.getReturn().getPromised()
}
}
/**
* Classes and predicates for modeling the `jsonfile` library (https://www.npmjs.com/package/jsonfile).
*/
private module JsonFile {
/**
* A reader for JSON files.
*/
class JsonFileReader extends FileSystemReadAccess, API::CallNode {
JsonFileReader() {
this = API::moduleImport("jsonfile").getMember(["readFile", "readFileSync"]).getACall()
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getADataNode() { result = this.trackRead().getAnImmediateUse() }
private API::Node trackRead() {
this.getCalleeName() = "readFile" and
(
result = this.getParameter([1 .. 2]).getParameter(1)
or
not exists(this.getCallback([1 .. 2])) and result = this.getReturn().getPromised()
)
or
this.getCalleeName() = "readFileSync" and
result = this.getReturn()
}
}
/** DEPRECATED: Alias for JsonFileReader */
deprecated class JSONFileReader = JsonFileReader;
/**
* A writer for JSON files.
*/
class JsonFileWriter extends FileSystemWriteAccess, DataFlow::CallNode {
JsonFileWriter() {
this =
DataFlow::moduleMember("jsonfile", any(string s | s = "writeFile" or s = "writeFileSync"))
.getACall()
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getADataNode() { result = this.getArgument(1) }
}
/** DEPRECATED: Alias for JsonFileWriter */
deprecated class JSONFileWriter = JsonFileWriter;
}
/**
* A call to the library `load-json-file`.
*/
private class LoadJsonFile extends FileSystemReadAccess, API::CallNode {
LoadJsonFile() {
this = API::moduleImport("load-json-file").getACall()
or
this = API::moduleImport("load-json-file").getMember("sync").getACall()
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getADataNode() { result = this.trackRead().getAnImmediateUse() }
private API::Node trackRead() {
this.getCalleeName() = "sync" and result = this.getReturn()
or
not this.getCalleeName() = "sync" and result = this.getReturn().getPromised()
}
}
/**
* A call to the library `write-json-file`.
*/
private class WriteJsonFile extends FileSystemWriteAccess, DataFlow::CallNode {
WriteJsonFile() {
this = DataFlow::moduleImport("write-json-file").getACall()
or
this = DataFlow::moduleMember("write-json-file", "sync").getACall()
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getADataNode() { result = this.getArgument(1) }
}
/**
* A call to the library `walkdir`.
*/
private class WalkDir extends FileNameProducer, FileSystemAccess, API::CallNode {
WalkDir() {
this = API::moduleImport("walkdir").getACall()
or
this = API::moduleImport("walkdir").getMember("sync").getACall()
or
this = API::moduleImport("walkdir").getMember("async").getACall()
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getAFileName() { result = this.trackFileSource().getAnImmediateUse() }
private API::Node trackFileSource() {
not this.getCalleeName() = ["sync", "async"] and
(
result = this.getParameter(this.getNumArgument() - 1).getParameter(0)
or
result = this.getReturn().getMember(EventEmitter::on()).getParameter(1).getParameter(0)
)
or
this.getCalleeName() = "sync" and result = this.getReturn()
or
this.getCalleeName() = "async" and result = this.getReturn().getPromised()
}
}
/**
* A call to the library `globule`.
*/
private class Globule extends FileNameProducer, FileSystemAccess, DataFlow::CallNode {
Globule() {
this = DataFlow::moduleMember("globule", "find").getACall()
or
this = DataFlow::moduleMember("globule", "match").getACall()
or
this = DataFlow::moduleMember("globule", "isMatch").getACall()
or
this = DataFlow::moduleMember("globule", "mapping").getACall()
or
this = DataFlow::moduleMember("globule", "findMapping").getACall()
}
override DataFlow::Node getAPathArgument() {
(this.getCalleeName() = "match" or this.getCalleeName() = "isMatch") and
result = this.getArgument(1)
or
this.getCalleeName() = "mapping" and
(
result = this.getAnArgument() and
not exists(result.getALocalSource().getAPropertyWrite("src"))
or
result = this.getAnArgument().getALocalSource().getAPropertyWrite("src").getRhs()
)
}
override DataFlow::Node getAFileName() {
result = this and
(
this.getCalleeName() = "find" or
this.getCalleeName() = "match" or
this.getCalleeName() = "findMapping" or
this.getCalleeName() = "mapping"
)
}
}
/**
* A file system access made by a NodeJS library.
* This class models multiple NodeJS libraries that access files.
*/
private class LibraryAccess extends FileSystemAccess, DataFlow::InvokeNode {
int pathArgument; // The index of the path argument.
LibraryAccess() {
pathArgument = 0 and
(
this = DataFlow::moduleImport("path-exists").getACall()
or
this = DataFlow::moduleImport("rimraf").getACall()
or
this = DataFlow::moduleImport("readdirp").getACall()
or
this = DataFlow::moduleImport("walker").getACall()
or
this =
DataFlow::moduleMember("node-dir",
["readFiles", "readFilesStream", "files", "promiseFiles", "subdirs", "paths"]).getACall()
)
or
pathArgument = 0 and
this =
DataFlow::moduleMember("vinyl-fs", any(string s | s = "src" or s = "dest" or s = "symlink"))
.getACall()
or
pathArgument = [0 .. 1] and
(
this = DataFlow::moduleImport("ncp").getACall() or
this = DataFlow::moduleMember("ncp", "ncp").getACall()
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArgument) }
}
/**
* A call to the library [`chokidar`](https://www.npmjs.com/package/chokidar), where a call to `on` receives file names.
*/
class Chokidar extends FileNameProducer, FileSystemAccess, API::CallNode {
Chokidar() { this = API::moduleImport("chokidar").getMember("watch").getACall() }
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getAFileName() {
exists(DataFlow::CallNode onCall, int pathIndex |
onCall = this.getAChainedMethodCall("on") and
if onCall.getArgument(0).mayHaveStringValue("all") then pathIndex = 1 else pathIndex = 0
|
result = onCall.getCallback(1).getParameter(pathIndex)
)
}
}
/**
* A call to the [`mkdirp`](https://www.npmjs.com/package/mkdirp) library.
*/
private class Mkdirp extends FileSystemAccess, API::CallNode {
Mkdirp() {
this = API::moduleImport("mkdirp").getACall()
or
this = API::moduleImport("mkdirp").getMember("sync").getACall()
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
}

View File

@@ -8,7 +8,20 @@ import semmle.javascript.Promises
/** Provices classes for modelling NoSQL query sinks. */
module NoSql {
/** An expression that is interpreted as a NoSQL query. */
abstract class Query extends Expr { }
abstract class Query extends Expr {
/** Gets an expression that is interpreted as a code operator in this query. */
DataFlow::Node getACodeOperator() { none() }
}
}
/** DEPRECATED: Alias for NoSql */
deprecated module NoSQL = NoSql;
/**
* Gets a value that has been assigned to the "$where" property of an object that flows to `queryArg`.
*/
private DataFlow::Node getADollarWhereProperty(API::Node queryArg) {
result = queryArg.getMember("$where").getARhs()
}
/**
@@ -16,112 +29,123 @@ module NoSql {
*/
private module MongoDB {
/**
* Gets an import of MongoDB.
*/
DataFlow::ModuleImportNode mongodb() { result.getPath() = "mongodb" }
/**
* Gets an access to `mongodb.MongoClient`.
*/
private DataFlow::SourceNode getAMongoClient(DataFlow::TypeTracker t) {
t.start() and
result = mongodb().getAPropertyRead("MongoClient")
or
exists(DataFlow::TypeTracker t2 | result = getAMongoClient(t2).track(t2, t))
}
/**
* Gets an access to `mongodb.MongoClient`.
*/
DataFlow::SourceNode getAMongoClient() { result = getAMongoClient(DataFlow::TypeTracker::end()) }
/** Gets a data flow node that leads to a `connect` callback. */
private DataFlow::SourceNode getAMongoDbCallback(DataFlow::TypeBackTracker t) {
t.start() and
result = getAMongoClient().getAMemberCall("connect").getArgument(1).getALocalSource()
or
exists(DataFlow::TypeBackTracker t2 | result = getAMongoDbCallback(t2).backtrack(t2, t))
}
/** Gets a data flow node that leads to a `connect` callback. */
private DataFlow::FunctionNode getAMongoDbCallback() {
result = getAMongoDbCallback(DataFlow::TypeBackTracker::end())
}
/**
* Gets an expression that may refer to a MongoDB database connection.
*/
private DataFlow::SourceNode getAMongoDb(DataFlow::TypeTracker t) {
t.start() and
result = getAMongoDbCallback().getParameter(1)
or
exists(DataFlow::TypeTracker t2 | result = getAMongoDb(t2).track(t2, t))
}
/**
* Gets an expression that may refer to a MongoDB database connection.
*/
DataFlow::SourceNode getAMongoDb() { result = getAMongoDb(DataFlow::TypeTracker::end()) }
/**
* A data flow node that may hold a MongoDB collection.
*/
abstract class Collection extends DataFlow::SourceNode { }
/**
* A collection resulting from calling `Db.collection(...)`.
*/
private class CollectionFromDb extends Collection {
CollectionFromDb() {
this = getAMongoDb().getAMethodCall("collection")
or
this = getAMongoDb().getAMethodCall("collection").getCallback(1).getParameter(0)
}
}
/**
* A collection based on the type `mongodb.Collection`.
* Gets an access to `mongodb.MongoClient` or a database.
*
* Note that this also covers `mongoose` models since they are subtypes
* of `mongodb.Collection`.
* In Mongo version 2.x, a client and a database handle were the same concept, but in 3.x
* they were separated. To handle everything with a single model, we treat them as the same here.
*/
private class CollectionFromType extends Collection {
CollectionFromType() { hasUnderlyingType("mongodb", "Collection") }
}
/** Gets a data flow node referring to a MongoDB collection. */
private DataFlow::SourceNode getACollection(DataFlow::TypeTracker t) {
t.start() and
result instanceof Collection
private API::Node getAMongoClientOrDatabase() {
result = API::moduleImport("mongodb").getMember("MongoClient")
or
exists(DataFlow::TypeTracker t2 | result = getACollection(t2).track(t2, t))
result = getAMongoClientOrDatabase().getMember("db").getReturn()
or
result = getAMongoClientOrDatabase().getMember("connect").getLastParameter().getParameter(1)
}
/** Gets a data flow node referring to a MongoDB collection. */
DataFlow::SourceNode getACollection() { result = getACollection(DataFlow::TypeTracker::end()) }
private API::Node getACollection() {
// A collection resulting from calling `Db.collection(...)`.
exists(API::Node collection |
collection = getAMongoClientOrDatabase().getMember("collection").getReturn()
|
result = collection
or
result = collection.getParameter(1).getParameter(0)
)
or
// note that this also covers `mongoose` models since they are subtypes of `mongodb.Collection`
result = API::Node::ofType("mongodb", "Collection")
}
/** A call to a MongoDB query method. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
private class QueryCall extends DatabaseAccess, API::CallNode {
int queryArgIdx;
QueryCall() {
exists(string m | this = getACollection().getAMethodCall(m) |
m = "count" and queryArgIdx = 0
or
m = "distinct" and queryArgIdx = 1
or
m = "find" and queryArgIdx = 0
exists(string method |
CollectionMethodSignatures::interpretsArgumentAsQuery(method, queryArgIdx) and
this = getACollection().getMember(method).getACall()
)
}
override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) }
override DataFlow::Node getAQueryArgument() { result = this.getArgument(queryArgIdx) }
override DataFlow::Node getAResult() {
PromiseFlow::loadStep(this.getALocalUse(), result, Promises::valueProp())
}
DataFlow::Node getACodeOperator() {
result = getADollarWhereProperty(this.getParameter(queryArgIdx))
}
}
/**
* An expression that is interpreted as a MongoDB query.
*/
class Query extends NoSQL::Query {
Query() { this = any(QueryCall qc).getAQueryArgument().asExpr() }
class Query extends NoSql::Query {
QueryCall qc;
Query() { this = qc.getAQueryArgument().asExpr() }
override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() }
}
/**
* Provides signatures for the Collection methods.
*/
module CollectionMethodSignatures {
/**
* Holds if Collection method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string name, int n) {
// FilterQuery
(
name = "aggregate" and n = 0
or
name = "count" and n = 0
or
name = "countDocuments" and n = 0
or
name = "deleteMany" and n = 0
or
name = "deleteOne" and n = 0
or
name = "distinct" and n = 1
or
name = "find" and n = 0
or
name = "findOne" and n = 0
or
name = "findOneAndDelete" and n = 0
or
name = "findOneAndRemove" and n = 0
or
name = "findOneAndReplace" and n = 0
or
name = "findOneAndUpdate" and n = 0
or
name = "remove" and n = 0
or
name = "replaceOne" and n = 0
or
name = "update" and n = 0
or
name = "updateMany" and n = 0
or
name = "updateOne" and n = 0
)
or
// UpdateQuery
(
name = "findOneAndUpdate" and n = 1
or
name = "update" and n = 1
or
name = "updateMany" and n = 1
or
name = "updateOne" and n = 1
)
}
}
}
@@ -132,20 +156,342 @@ private module Mongoose {
/**
* Gets an import of Mongoose.
*/
DataFlow::ModuleImportNode getAMongooseInstance() { result.getPath() = "mongoose" }
API::Node getAMongooseInstance() { result = API::moduleImport("mongoose") }
/**
* Gets a call to `mongoose.createConnection`.
* Gets a reference to `mongoose.createConnection`.
*/
DataFlow::CallNode createConnection() {
result = getAMongooseInstance().getAMemberCall("createConnection")
API::Node createConnection() { result = getAMongooseInstance().getMember("createConnection") }
/**
* A Mongoose function.
*/
abstract private class MongooseFunction extends API::Node {
/**
* Gets the API-graph node for the result from this function (if the function returns a `Query`).
*/
abstract API::Node getQueryReturn();
/**
* Holds if this function returns a `Query` that evaluates to one or
* more Documents (`asArray` is false if it evaluates to a single
* Document).
*/
abstract predicate returnsDocumentQuery(boolean asArray);
/**
* Gets an argument that this function interprets as a query.
*/
abstract API::Node getQueryArgument();
}
/**
* A Mongoose collection object.
* Provides classes modeling the Mongoose Model class
*/
class Model extends MongoDB::Collection {
Model() { this = getAMongooseInstance().getAMemberCall("model") }
module Model {
private class ModelFunction extends MongooseFunction {
string methodName;
ModelFunction() { this = getModelObject().getMember(methodName) }
override API::Node getQueryReturn() {
MethodSignatures::returnsQuery(methodName) and result = this.getReturn()
}
override predicate returnsDocumentQuery(boolean asArray) {
MethodSignatures::returnsDocumentQuery(methodName, asArray)
}
override API::Node getQueryArgument() {
exists(int n |
MethodSignatures::interpretsArgumentAsQuery(methodName, n) and
result = this.getParameter(n)
)
}
}
/**
* Gets a API-graph node referring to a Mongoose Model object.
*/
private API::Node getModelObject() {
result = getAMongooseInstance().getMember("model").getReturn()
or
exists(API::Node conn | conn = createConnection().getReturn() |
result = conn.getMember("model").getReturn() or
result = conn.getMember("models").getAMember()
)
or
result = API::Node::ofType("mongoose", "Model")
}
/**
* Provides signatures for the Model methods.
*/
module MethodSignatures {
/**
* Holds if Model method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string name, int n) {
// implement lots of the MongoDB collection interface
MongoDB::CollectionMethodSignatures::interpretsArgumentAsQuery(name, n)
or
name = "find" + ["ById", "One"] + "AndUpdate" and n = 1
or
name in ["delete" + ["Many", "One"], "geoSearch", "remove", "replaceOne", "where"] and
n = 0
or
name in [
"find" + ["", "ById", "One"],
"find" + ["ById", "One"] + "And" + ["Delete", "Remove", "Update"],
"update" + ["", "Many", "One"]
] and
n = 0
}
/**
* Holds if Model method `name` returns a Query.
*/
predicate returnsQuery(string name) {
name =
[
"$where", "count", "findOne", "findOneAndDelete", "findOneAndRemove",
"findOneAndReplace", "findOneAndUpdate", "geosearch", "remove", "replaceOne", "update",
"updateMany", "countDocuments", "updateOne", "where", "deleteMany", "deleteOne", "find",
"findById", "findByIdAndDelete", "findByIdAndRemove", "findByIdAndUpdate"
]
}
/**
* Holds if Document method `name` returns a query that results in
* one or more documents, the documents are wrapped in an array
* if `asArray` is true.
*/
predicate returnsDocumentQuery(string name, boolean asArray) {
asArray = false and name = "findOne"
or
asArray = true and name = "find"
}
}
}
/**
* Provides classes modeling the Mongoose Query class
*/
module Query {
private class QueryFunction extends MongooseFunction {
string methodName;
QueryFunction() { this = getAMongooseQuery().getMember(methodName) }
override API::Node getQueryReturn() {
MethodSignatures::returnsQuery(methodName) and result = this.getReturn()
}
override predicate returnsDocumentQuery(boolean asArray) {
MethodSignatures::returnsDocumentQuery(methodName, asArray)
}
override API::Node getQueryArgument() {
exists(int n |
MethodSignatures::interpretsArgumentAsQuery(methodName, n) and
result = this.getParameter(n)
)
}
}
private class NewQueryFunction extends MongooseFunction {
NewQueryFunction() { this = getAMongooseInstance().getMember("Query") }
override API::Node getQueryReturn() { result = this.getInstance() }
override predicate returnsDocumentQuery(boolean asArray) { none() }
override API::Node getQueryArgument() { result = this.getParameter(2) }
}
/**
* Gets a data flow node referring to a Mongoose query object.
*/
API::Node getAMongooseQuery() {
result = any(MongooseFunction f).getQueryReturn()
or
result = API::Node::ofType("mongoose", "Query")
or
result =
getAMongooseQuery()
.getMember(any(string name | MethodSignatures::returnsQuery(name)))
.getReturn()
}
/**
* Provides signatures for the Query methods.
*/
module MethodSignatures {
/**
* Holds if Query method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string name, int n) {
n = 0 and
name =
[
"and", "count", "findOneAndReplace", "findOneAndUpdate", "merge", "nor", "or", "remove",
"replaceOne", "setQuery", "setUpdate", "update", "countDocuments", "updateMany",
"updateOne", "where", "deleteMany", "deleteOne", "elemMatch", "find", "findOne",
"findOneAndDelete", "findOneAndRemove"
]
or
n = 1 and
name = ["distinct", "findOneAndUpdate", "update", "updateMany", "updateOne"]
}
/**
* Holds if Query method `name` returns a Query.
*/
predicate returnsQuery(string name) {
name =
[
"$where", "J", "comment", "count", "countDocuments", "distinct", "elemMatch", "equals",
"error", "estimatedDocumentCount", "exists", "explain", "all", "find", "findById",
"findOne", "findOneAndRemove", "findOneAndUpdate", "geometry", "get", "gt", "gte",
"hint", "and", "in", "intersects", "lean", "limit", "lt", "lte", "map", "map",
"maxDistance", "maxTimeMS", "batchsize", "maxscan", "mod", "ne", "near", "nearSphere",
"nin", "or", "orFail", "polygon", "populate", "box", "read", "readConcern", "regexp",
"remove", "select", "session", "set", "setOptions", "setQuery", "setUpdate", "center",
"size", "skip", "slaveOk", "slice", "snapshot", "sort", "update", "w", "where",
"within", "centerSphere", "wtimeout", "circle", "collation"
]
}
/**
* Holds if Query method `name` returns a query that results in
* one or more documents, the documents are wrapped in an array
* if `asArray` is true.
*/
predicate returnsDocumentQuery(string name, boolean asArray) {
asArray = false and name = "findOne"
or
asArray = true and name = "find"
}
}
}
/**
* Provides classes modeling the Mongoose Document class
*/
module Document {
private class DocumentFunction extends MongooseFunction {
string methodName;
DocumentFunction() { this = getAMongooseDocument().getMember(methodName) }
override API::Node getQueryReturn() {
MethodSignatures::returnsQuery(methodName) and result = this.getReturn()
}
override predicate returnsDocumentQuery(boolean asArray) {
MethodSignatures::returnsDocumentQuery(methodName, asArray)
}
override API::Node getQueryArgument() {
exists(int n |
MethodSignatures::interpretsArgumentAsQuery(methodName, n) and
result = this.getParameter(n)
)
}
}
/**
* A Mongoose Document that is retrieved from the backing database.
*/
class RetrievedDocument extends API::Node {
RetrievedDocument() {
exists(boolean asArray, API::Node param |
exists(MongooseFunction func |
func.returnsDocumentQuery(asArray) and
param = func.getLastParameter().getParameter(1)
)
or
exists(API::Node f |
f = Query::getAMongooseQuery().getMember("then") and
param = f.getParameter(0).getParameter(0)
or
f = Query::getAMongooseQuery().getMember("exec") and
param = f.getParameter(0).getParameter(1)
|
exists(DataFlow::MethodCallNode pred |
// limitation: look at the previous method call
Query::MethodSignatures::returnsDocumentQuery(pred.getMethodName(), asArray) and
pred.getAMethodCall() = f.getACall()
)
)
|
asArray = false and this = param
or
asArray = true and
// limitation: look for direct accesses
this = param.getUnknownMember()
)
}
}
/**
* Gets a data flow node referring to a Mongoose Document object.
*/
private API::Node getAMongooseDocument() {
result instanceof RetrievedDocument
or
result = API::Node::ofType("mongoose", "Document")
or
result =
getAMongooseDocument()
.getMember(any(string name | MethodSignatures::returnsDocument(name)))
.getReturn()
}
private module MethodSignatures {
/**
* Holds if Document method `name` returns a Query.
*/
predicate returnsQuery(string name) {
// Documents are subtypes of Models
Model::MethodSignatures::returnsQuery(name) or
name = "replaceOne" or
name = "update" or
name = "updateOne"
}
/**
* Holds if Document method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string name, int n) {
// Documents are subtypes of Models
Model::MethodSignatures::interpretsArgumentAsQuery(name, n)
or
n = 0 and
(
name = "replaceOne" or
name = "update" or
name = "updateOne"
)
}
/**
* Holds if Document method `name` returns a query that results in
* one or more documents, the documents are wrapped in an array
* if `asArray` is true.
*/
predicate returnsDocumentQuery(string name, boolean asArray) {
// Documents are subtypes of Models
Model::MethodSignatures::returnsDocumentQuery(name, asArray)
}
/**
* Holds if Document method `name` returns a Document.
*/
predicate returnsDocument(string name) {
name = ["depopulate", "init", "populate", "overwrite"]
}
}
}
/**
@@ -155,7 +501,9 @@ private module Mongoose {
string kind;
Credentials() {
exists(string prop | this = createConnection().getOptionArgument(3, prop).asExpr() |
exists(string prop |
this = createConnection().getParameter(3).getMember(prop).getARhs().asExpr()
|
prop = "user" and kind = "user name"
or
prop = "pass" and kind = "password"
@@ -164,4 +512,308 @@ private module Mongoose {
override string getCredentialsKind() { result = kind }
}
/**
* An expression that is interpreted as a (part of a) MongoDB query.
*/
class MongoDBQueryPart extends NoSql::Query {
MongooseFunction f;
MongoDBQueryPart() { this = f.getQueryArgument().getARhs().asExpr() }
override DataFlow::Node getACodeOperator() {
result = getADollarWhereProperty(f.getQueryArgument())
}
}
/**
* An evaluation of a MongoDB query.
*/
class ShorthandQueryEvaluation extends DatabaseAccess, DataFlow::InvokeNode {
MongooseFunction f;
ShorthandQueryEvaluation() {
this = f.getACall() and
// shorthand for execution: provide a callback
exists(f.getQueryReturn()) and
exists(this.getCallback(this.getNumArgument() - 1))
}
override DataFlow::Node getAQueryArgument() {
// NB: the complete information is not easily accessible for deeply chained calls
f.getQueryArgument().getARhs() = result
}
override DataFlow::Node getAResult() {
result = this.getCallback(this.getNumArgument() - 1).getParameter(1)
}
}
class ExplicitQueryEvaluation extends DatabaseAccess, DataFlow::CallNode {
string member;
ExplicitQueryEvaluation() {
// explicit execution using a Query method call
member = ["exec", "then", "catch"] and
Query::getAMongooseQuery().getMember(member).getACall() = this
}
private int resultParamIndex() {
member = "then" and result = 0
or
member = "exec" and result = 1
}
override DataFlow::Node getAResult() {
result = this.getCallback(_).getParameter(this.resultParamIndex())
}
override DataFlow::Node getAQueryArgument() {
// NB: the complete information is not easily accessible for deeply chained calls
none()
}
}
}
/**
* Provides classes modeling the Minimongo library.
*/
private module Minimongo {
/**
* Provides signatures for the Collection methods.
*/
module CollectionMethodSignatures {
/**
* Holds if Collection method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string m, int queryArgIdx) {
// implements most of the MongoDB interface
MongoDB::CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx)
}
}
/** A call to a Minimongo query method. */
private class QueryCall extends DatabaseAccess, API::CallNode {
int queryArgIdx;
QueryCall() {
exists(string m |
this =
API::moduleImport("minimongo")
.getAMember()
.getReturn()
.getAMember()
.getMember(m)
.getACall() and
CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx)
)
}
override DataFlow::Node getAQueryArgument() { result = this.getArgument(queryArgIdx) }
override DataFlow::Node getAResult() {
PromiseFlow::loadStep(this.getALocalUse(), result, Promises::valueProp())
}
DataFlow::Node getACodeOperator() {
result = getADollarWhereProperty(this.getParameter(queryArgIdx))
}
}
/**
* An expression that is interpreted as a Minimongo query.
*/
class Query extends NoSql::Query {
QueryCall qc;
Query() { this = qc.getAQueryArgument().asExpr() }
override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() }
}
}
/**
* Provides classes modeling the MarsDB library.
*/
private module MarsDB {
private class MarsDBAccess extends DatabaseAccess, DataFlow::CallNode {
string method;
MarsDBAccess() {
this =
API::moduleImport("marsdb")
.getMember("Collection")
.getInstance()
.getMember(method)
.getACall()
}
string getMethod() { result = method }
override DataFlow::Node getAResult() {
PromiseFlow::loadStep(this.getALocalUse(), result, Promises::valueProp())
}
override DataFlow::Node getAQueryArgument() { none() }
}
/** A call to a MarsDB query method. */
private class QueryCall extends MarsDBAccess, API::CallNode {
int queryArgIdx;
QueryCall() {
exists(string m |
this.getMethod() = m and
// implements parts of the Minimongo interface
Minimongo::CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx)
)
}
override DataFlow::Node getAResult() {
PromiseFlow::loadStep(this.getALocalUse(), result, Promises::valueProp())
}
override DataFlow::Node getAQueryArgument() { result = this.getArgument(queryArgIdx) }
DataFlow::Node getACodeOperator() {
result = getADollarWhereProperty(this.getParameter(queryArgIdx))
}
}
/**
* An expression that is interpreted as a MarsDB query.
*/
class Query extends NoSql::Query {
QueryCall qc;
Query() { this = qc.getAQueryArgument().asExpr() }
override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() }
}
}
/**
* Provides classes modeling the `Node Redis` library.
*
* Redis is an in-memory key-value store and not a database,
* but `Node Redis` can be exploited similarly to a NoSQL database by giving a method an array as argument instead of a string.
* As an example the below two invocations of `client.set` are equivalent:
*
* ```
* const redis = require("redis");
* const client = redis.createClient();
* client.set("key", "value");
* client.set(["key", "value"]);
* ```
*
* ioredis is a very similar library. However, ioredis does not support array arguments in the same way, and is therefore not vulnerable to the same kind of type confusion.
*/
private module Redis {
/**
* Gets a `Node Redis` client.
*/
private API::Node client() {
result = API::moduleImport("redis").getMember("createClient").getReturn()
or
result = API::moduleImport("redis").getMember("RedisClient").getInstance()
or
result = client().getMember("duplicate").getReturn()
or
result = client().getMember("duplicate").getLastParameter().getParameter(1)
}
/**
* Gets a (possibly chained) reference to a batch operation object.
* These have the same API as a redis client, except the calls are chained, and the sequence is terminated with a `.exec` call.
*/
private API::Node multi() {
result = client().getMember(["multi", "batch"]).getReturn()
or
result = multi().getAMember().getReturn()
}
/**
* Gets a `Node Redis` client instance. Either a client created using `createClient()`, or a batch operation object.
*/
private API::Node redis() { result = [client(), multi()] }
/**
* Provides signatures for the query methods from Node Redis.
*/
module QuerySignatures {
/**
* Holds if `method` interprets parameter `argIndex` as a key, and a later parameter determines a value/field.
* Thereby the method is vulnerable if parameter `argIndex` is unexpectedly an array instead of a string, as an attacker can control arguments to Redis that the attacker was not supposed to control.
*
* Only setters and similar methods are included.
* For getter-like methods it is not generally possible to gain access "outside" of where you are supposed to have access,
* it is at most possible to get a Redis call to return more results than expected (e.g. by adding more members to [`geohash`](https://redis.io/commands/geohash)).
*/
predicate argumentIsAmbiguousKey(string method, int argIndex) {
method =
[
"set", "publish", "append", "bitfield", "decrby", "getset", "hincrby", "hincrbyfloat",
"hset", "hsetnx", "incrby", "incrbyfloat", "linsert", "lpush", "lpushx", "lset", "ltrim",
"rename", "renamenx", "rpushx", "setbit", "setex", "smove", "zincrby", "zinterstore",
"hdel", "lpush", "pfadd", "rpush", "sadd", "sdiffstore", "srem"
] and
argIndex = 0
or
method = ["bitop", "hmset", "mset", "msetnx", "geoadd"] and
argIndex in [0 .. any(DataFlow::InvokeNode invk).getNumArgument() - 1]
}
}
/**
* An expression that is interpreted as a key in a Node Redis call.
*/
class RedisKeyArgument extends NoSql::Query {
RedisKeyArgument() {
exists(string method, int argIndex |
QuerySignatures::argumentIsAmbiguousKey(method, argIndex) and
this = redis().getMember(method).getParameter(argIndex).getARhs().asExpr()
)
}
}
/**
* An access to a database through redis
*/
class RedisDatabaseAccess extends DatabaseAccess, DataFlow::CallNode {
RedisDatabaseAccess() { this = redis().getMember(_).getACall() }
override DataFlow::Node getAResult() {
PromiseFlow::loadStep(this.getALocalUse(), result, Promises::valueProp())
}
override DataFlow::Node getAQueryArgument() { none() }
}
}
/**
* Provides classes modeling the `ioredis` library.
*
* ```
* import Redis from 'ioredis'
* let client = new Redis(...)
* ```
*/
private module IoRedis {
/**
* Gets an `ioredis` client.
*/
API::Node ioredis() { result = API::moduleImport("ioredis").getInstance() }
/**
* An access to a database through ioredis
*/
class IoRedisDatabaseAccess extends DatabaseAccess, DataFlow::CallNode {
IoRedisDatabaseAccess() { this = ioredis().getMember(_).getACall() }
override DataFlow::Node getAResult() {
PromiseFlow::loadStep(this.getALocalUse(), result, Promises::valueProp())
}
override DataFlow::Node getAQueryArgument() { none() }
}
}

View File

@@ -493,11 +493,56 @@ module NodeJSLib {
*/
module FS {
/**
* A member `member` from module `fs`.
* Gets a member `member` from module `fs` or its drop-in replacements `graceful-fs`, `fs-extra`, `original-fs`.
*/
DataFlow::SourceNode moduleMember(string member) {
exists(string moduleName | moduleName = ["fs"] |
result = DataFlow::moduleMember(moduleName, member)
result = fsModule(DataFlow::TypeTracker::end()).getAPropertyRead(member)
}
private DataFlow::SourceNode fsModule(DataFlow::TypeTracker t) {
exists(string moduleName |
moduleName = ["mz/fs", "original-fs", "fs-extra", "graceful-fs", "fs"]
|
result = DataFlow::moduleImport(moduleName)
or
// extra support for flexible names
result.asExpr().(Require).getArgument(0).mayHaveStringValue(moduleName)
) and
t.start()
or
t.start() and
result = DataFlow::moduleMember("fs", "promises")
or
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred | pred = fsModule(t2) |
result = pred.track(t2, t)
or
t.continue() = t2 and
exists(Promisify::PromisifyAllCall promisifyAllCall |
result = promisifyAllCall and
pred.flowsTo(promisifyAllCall.getArgument(0))
)
or
// const fs = require('fs');
// let fs_copy = methods.reduce((obj, method) => {
// obj[method] = fs[method];
// return obj;
// }, {});
t.continue() = t2 and
exists(
DataFlow::MethodCallNode call, DataFlow::ParameterNode obj, DataFlow::SourceNode method
|
call.getMethodName() = "reduce" and
result = call and
obj = call.getABoundCallbackParameter(0, 0) and
obj.flowsTo(any(DataFlow::FunctionNode f).getAReturn()) and
exists(DataFlow::PropWrite write, DataFlow::PropRead read |
write = obj.getAPropertyWrite() and
method.flowsToExpr(write.getPropertyNameExpr()) and
method.flowsToExpr(read.getPropertyNameExpr()) and
read.getBase().getALocalSource() = fsModule(t2) and
write.getRhs() = maybePromisified(read)
)
)
)
}
}
@@ -508,7 +553,7 @@ module NodeJSLib {
private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode {
string methodName;
NodeJSFileSystemAccess() { this = FS::moduleMember(methodName).getACall() }
NodeJSFileSystemAccess() { this = maybePromisified(FS::moduleMember(methodName)).getACall() }
/**
* Gets the name of the called method.

View File

@@ -33,38 +33,54 @@ module SQL {
* Provides classes modeling the (API compatible) `mysql` and `mysql2` packages.
*/
private module MySql {
private DataFlow::SourceNode mysql() { result = DataFlow::moduleImport(["mysql", "mysql2"]) }
private string moduleName() { result = ["mysql", "mysql2", "mysql2/promise"] }
private DataFlow::CallNode createPool() { result = mysql().getAMemberCall("createPool") }
/** Gets the package name `mysql` or `mysql2`. */
API::Node mysql() { result = API::moduleImport(moduleName()) }
/** Gets a reference to a MySQL pool. */
private DataFlow::SourceNode pool(DataFlow::TypeTracker t) {
t.start() and
result = createPool()
/** Gets a reference to `mysql.createConnection`. */
API::Node createConnection() {
result = mysql().getMember(["createConnection", "createConnectionPromise"])
}
/** Gets a reference to a MySQL pool. */
private DataFlow::SourceNode pool() { result = pool(DataFlow::TypeTracker::end()) }
/** Gets a reference to `mysql.createPool`. */
API::Node createPool() { result = mysql().getMember(["createPool", "createPoolCluster"]) }
/** Gets a call to `mysql.createConnection`. */
DataFlow::CallNode createConnection() { result = mysql().getAMemberCall("createConnection") }
/** Gets a node that contains a MySQL pool created using `mysql.createPool()`. */
API::Node pool() {
result = createPool().getReturn()
or
result = pool().getMember("on").getReturn()
or
result = API::Node::ofType(moduleName(), ["Pool", "PoolCluster"])
}
/** Gets a reference to a MySQL connection instance. */
private DataFlow::SourceNode connection(DataFlow::TypeTracker t) {
t.start() and
(
result = createConnection()
or
result = pool().getAMethodCall("getConnection").getABoundCallbackParameter(0, 1)
/** Gets a data flow node that contains a freshly created MySQL connection instance. */
API::Node connection() {
result = createConnection().getReturn()
or
result = createConnection().getReturn().getPromised()
or
result = pool().getMember("getConnection").getParameter(0).getParameter(1)
or
result = pool().getMember("getConnection").getPromised()
or
exists(API::CallNode call |
call = pool().getMember("on").getACall() and
call.getArgument(0).getStringValue() = ["connection", "acquire", "release"] and
result = call.getParameter(1).getParameter(0)
)
or
result = API::Node::ofType(moduleName(), ["Connection", "PoolConnection"])
}
/** Gets a reference to a MySQL connection instance. */
DataFlow::SourceNode connection() { result = connection(DataFlow::TypeTracker::end()) }
/** A call to the MySql `query` method. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
QueryCall() { this = [pool(), connection()].getAMethodCall("query") }
QueryCall() {
exists(API::Node recv | recv = pool() or recv = connection() |
this = recv.getMember(["query", "execute"]).getACall()
)
}
override DataFlow::Node getAResult() { result = this.getCallback(_).getParameter(1) }
@@ -81,7 +97,7 @@ private module MySql {
/** A call to the `escape` or `escapeId` method that performs SQL sanitization. */
class EscapingSanitizer extends SQL::SqlSanitizer, MethodCallExpr {
EscapingSanitizer() {
this = [mysql(), pool(), connection()].getAMethodCall(["escape", "escapeId"]).asExpr() and
this = [mysql(), pool(), connection()].getMember(["escape", "escapeId"]).getACall().asExpr() and
input = this.getArgument(0) and
output = this
}
@@ -92,8 +108,9 @@ private module MySql {
string kind;
Credentials() {
exists(string prop |
this = [createConnection(), createPool()].getOptionArgument(0, prop).asExpr() and
exists(API::Node callee, string prop |
callee in [createConnection(), createPool()] and
this = callee.getParameter(0).getMember(prop).getARhs().asExpr() and
(
prop = "user" and kind = "user name"
or
@@ -110,23 +127,61 @@ private module MySql {
* Provides classes modeling the PostgreSQL packages, such as `pg` and `pg-promise`.
*/
private module Postgres {
/** Gets an expression that constructs a new connection pool. */
DataFlow::InvokeNode newPool() {
// new require('pg').Pool()
result = DataFlow::moduleImport("pg").getAConstructorInvocation("Pool")
API::Node pg() {
result = API::moduleImport("pg")
or
// new require('pg-pool')
result = DataFlow::moduleImport("pg-pool").getAnInstantiation()
result = pgpMain().getMember("pg")
}
/** Gets a creation of a Postgres client. */
DataFlow::InvokeNode newClient() {
result = DataFlow::moduleImport("pg").getAConstructorInvocation("Client")
/** Gets a reference to the `Client` constructor in the `pg` package, for example `require('pg').Client`. */
API::Node newClient() { result = pg().getMember("Client") }
/** Gets a freshly created Postgres client instance. */
API::Node client() {
result = newClient().getInstance()
or
// pool.connect(function(err, client) { ... })
result = pool().getMember("connect").getParameter(0).getParameter(1)
or
// await pool.connect()
result = pool().getMember("connect").getReturn().getPromised()
or
result = pgpConnection().getMember("client")
or
exists(API::CallNode call |
call = pool().getMember("on").getACall() and
call.getArgument(0).getStringValue() = ["connect", "acquire"] and
result = call.getParameter(1).getParameter(0)
)
or
result = client().getMember("on").getReturn()
or
result = API::Node::ofType("pg", ["Client", "PoolClient"])
}
/** Gets a constructor that when invoked constructs a new connection pool. */
API::Node newPool() {
// new require('pg').Pool()
result = pg().getMember("Pool")
or
// new require('pg-pool')
result = API::moduleImport("pg-pool")
}
/** Gets an API node that refers to a connection pool. */
API::Node pool() {
result = newPool().getInstance()
or
result = pgpDatabase().getMember("$pool")
or
result = pool().getMember("on").getReturn()
or
result = API::Node::ofType("pg", "Pool")
}
/** A call to the Postgres `query` method. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
QueryCall() { this = [newClient(), newPool()].getAMethodCall("query") }
QueryCall() { this = [client(), pool()].getMember("query").getACall() }
override DataFlow::Node getAResult() {
this.getNumArgument() = 2 and
@@ -155,7 +210,11 @@ private module Postgres {
string kind;
Credentials() {
exists(string prop | this = [newClient(), newPool()].getOptionArgument(0, prop).asExpr() |
exists(string prop |
this = [newClient(), newPool()].getParameter(0).getMember(prop).getARhs().asExpr()
or
this = pgPromise().getParameter(0).getMember(prop).getARhs().asExpr()
|
prop = "user" and kind = "user name"
or
prop = "password" and kind = prop
@@ -300,30 +359,35 @@ private module Postgres {
*/
private module Sqlite {
/** Gets a reference to the `sqlite3` module. */
DataFlow::SourceNode sqlite() {
result = DataFlow::moduleImport("sqlite3")
API::Node sqlite() {
result = API::moduleImport("sqlite3")
or
result = sqlite().getAMemberCall("verbose")
result = sqlite().getMember("verbose").getReturn()
}
/** Gets an expression that constructs a Sqlite database instance. */
DataFlow::SourceNode newDb() {
/** Gets an expression that constructs or returns a Sqlite database instance. */
API::Node database() {
// new require('sqlite3').Database()
result = sqlite().getAConstructorInvocation("Database")
result = sqlite().getMember("Database").getInstance()
or
// chained call
result = getAChainingQueryCall()
or
result = API::Node::ofType("sqlite3", "Database")
}
/** Gets a data flow node referring to a Sqlite database instance. */
private DataFlow::SourceNode db(DataFlow::TypeTracker t) {
t.start() and
result = newDb()
/** Gets a call to a query method on a Sqlite database instance that returns the same instance. */
private API::Node getAChainingQueryCall() {
result = database().getMember(["all", "each", "exec", "get", "run"]).getReturn()
}
/** Gets a data flow node referring to a Sqlite database instance. */
DataFlow::SourceNode db() { result = db(DataFlow::TypeTracker::end()) }
/** A call to a Sqlite query method. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
QueryCall() { this = db().getAMethodCall(["all", "each", "exec", "get", "prepare", "run"]) }
QueryCall() {
this = getAChainingQueryCall().getAnImmediateUse()
or
this = database().getMember("prepare").getACall()
}
override DataFlow::Node getAResult() {
result = this.getCallback(1).getParameter(1) or
@@ -338,3 +402,203 @@ private module Sqlite {
QueryString() { this = any(QueryCall qc).getAQueryArgument().asExpr() }
}
}
/**
* Provides classes modeling the `mssql` package.
*/
private module MsSql {
/** Gets a reference to the `mssql` module. */
API::Node mssql() { result = API::moduleImport("mssql") }
/** Gets a node referring to an instance of the given class. */
API::Node mssqlClass(string name) {
result = mssql().getMember(name).getInstance()
or
result = API::Node::ofType("mssql", name)
}
/** Gets an API node referring to a Request object. */
API::Node request() {
result = mssqlClass("Request")
or
result = request().getMember(["input", "replaceInput", "output", "replaceOutput"]).getReturn()
or
result = [transaction(), pool()].getMember("request").getReturn()
}
/** Gets an API node referring to a Transaction object. */
API::Node transaction() {
result = mssqlClass("Transaction")
or
result = pool().getMember("transaction").getReturn()
}
/** Gets a API node referring to a ConnectionPool object. */
API::Node pool() { result = mssqlClass("ConnectionPool") }
/** A tagged template evaluated as a query. */
private class QueryTemplateExpr extends DatabaseAccess, DataFlow::ValueNode, DataFlow::SourceNode {
override TaggedTemplateExpr astNode;
QueryTemplateExpr() {
mssql().getMember("query").getAUse() = DataFlow::valueNode(astNode.getTag())
}
override DataFlow::Node getAResult() {
PromiseFlow::loadStep(this.getALocalUse(), result, Promises::valueProp())
}
override DataFlow::Node getAQueryArgument() {
result = DataFlow::valueNode(astNode.getTemplate().getAnElement())
}
}
/** A call to a MsSql query method. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
QueryCall() { this = [mssql(), request()].getMember(["query", "batch"]).getACall() }
override DataFlow::Node getAResult() {
result = this.getCallback(1).getParameter(1)
or
PromiseFlow::loadStep(this.getALocalUse(), result, Promises::valueProp())
}
override DataFlow::Node getAQueryArgument() { result = this.getArgument(0) }
}
/** An expression that is passed to a method that interprets it as SQL. */
class QueryString extends SQL::SqlString {
QueryString() {
exists(DatabaseAccess dba | dba instanceof QueryTemplateExpr or dba instanceof QueryCall |
this = dba.getAQueryArgument().asExpr()
)
}
}
/** An element of a query template, which is automatically sanitized. */
class QueryTemplateSanitizer extends SQL::SqlSanitizer {
QueryTemplateSanitizer() {
this = any(QueryTemplateExpr qte).getAQueryArgument().asExpr() and
input = this and
output = this
}
}
/** An expression that is passed as user name or password when creating a client or a pool. */
class Credentials extends CredentialsExpr {
string kind;
Credentials() {
exists(API::Node callee, string prop |
(
callee = mssql().getMember("connect")
or
callee = mssql().getMember("ConnectionPool")
) and
this = callee.getParameter(0).getMember(prop).getARhs().asExpr() and
(
prop = "user" and kind = "user name"
or
prop = "password" and kind = prop
)
)
}
override string getCredentialsKind() { result = kind }
}
}
/**
* Provides classes modeling the `sequelize` package.
*/
private module Sequelize {
class SequelizeModel extends ModelInput::TypeModelCsv {
override predicate row(string row) {
// package1;type1;package2;type2;path
row =
[
"sequelize;;sequelize-typescript;;", //
"sequelize;Sequelize;sequelize;default;", //
"sequelize;Sequelize;sequelize;;Instance",
"sequelize;Sequelize;sequelize;;Member[Sequelize].Instance",
]
}
}
class SequelizeSink extends ModelInput::SinkModelCsv {
override predicate row(string row) {
row =
[
"sequelize;Sequelize;Member[query].Argument[0];sql-injection",
"sequelize;Sequelize;Member[query].Argument[0].Member[query];sql-injection",
"sequelize;;Member[literal,asIs].Argument[0];sql-injection",
"sequelize;;Argument[1];credentials[user name]",
"sequelize;;Argument[2];credentials[password]",
"sequelize;;Argument[0..].Member[username];credentials[user name]",
"sequelize;;Argument[0..].Member[password];credentials[password]"
]
}
}
class SequelizeSource extends ModelInput::SourceModelCsv {
override predicate row(string row) {
row = "sequelize;Sequelize;Member[query].ReturnValue.Awaited;database-access-result"
}
}
}
private module SpannerCsv {
class SpannerTypes extends ModelInput::TypeModelCsv {
override predicate row(string row) {
// package1; type1; package2; type2; path
row =
[
"@google-cloud/spanner;;@google-cloud/spanner;;Member[Spanner]",
"@google-cloud/spanner;Database;@google-cloud/spanner;;ReturnValue.Member[instance].ReturnValue.Member[database].ReturnValue",
"@google-cloud/spanner;v1.SpannerClient;@google-cloud/spanner;;Member[v1].Member[SpannerClient].Instance",
"@google-cloud/spanner;Transaction;@google-cloud/spanner;Database;Member[runTransaction,runTransactionAsync,getTransaction].Argument[0..1].Parameter[1]",
"@google-cloud/spanner;Transaction;@google-cloud/spanner;Database;Member[getTransaction].ReturnValue.Awaited",
"@google-cloud/spanner;Snapshot;@google-cloud/spanner;Database;Member[getSnapshot].Argument[0..1].Parameter[1]",
"@google-cloud/spanner;Snapshot;@google-cloud/spanner;Database;Member[getSnapshot].ReturnValue.Awaited",
"@google-cloud/spanner;BatchTransaction;@google-cloud/spanner;Database;Member[batchTransaction].ReturnValue",
"@google-cloud/spanner;BatchTransaction;@google-cloud/spanner;Database;Member[createBatchTransaction].ReturnValue.Awaited",
"@google-cloud/spanner;~SqlExecutorDirect;@google-cloud/spanner;Database;Member[run,runPartitionedUpdate,runStream]",
"@google-cloud/spanner;~SqlExecutorDirect;@google-cloud/spanner;Transaction;Member[run,runStream,runUpdate]",
"@google-cloud/spanner;~SqlExecutorDirect;@google-cloud/spanner;BatchTransaction;Member[createQueryPartitions]",
]
}
}
class SpannerSinks extends ModelInput::SinkModelCsv {
override predicate row(string row) {
// package; type; path; kind
row =
[
"@google-cloud/spanner;~SqlExecutorDirect;Argument[0];sql-injection",
"@google-cloud/spanner;~SqlExecutorDirect;Argument[0].Member[sql];sql-injection",
"@google-cloud/spanner;Transaction;Member[batchUpdate].Argument[0];sql-injection",
"@google-cloud/spanner;Transaction;Member[batchUpdate].Argument[0].ArrayElement.Member[sql];sql-injection",
"@google-cloud/spanner;v1.SpannerClient;Member[executeSql,executeStreamingSql].Argument[0].Member[sql];sql-injection",
]
}
}
class SpannerSources extends ModelInput::SourceModelCsv {
string spannerClass() { result = ["v1.SpannerClient", "Database", "Transaction", "Snapshot",] }
string resultPath() {
result =
[
"Member[executeSql].Argument[0..].Parameter[1]",
"Member[executeSql].ReturnValue.Awaited.Member[0]", "Member[run].ReturnValue.Awaited",
"Member[run].Argument[0..].Parameter[1]",
]
}
override predicate row(string row) {
row =
"@google-cloud/spanner;" + this.spannerClass() + ";" + this.resultPath() +
";database-access-result"
}
}
}

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