Compare commits

..

154 Commits

Author SHA1 Message Date
Robert Marsh
7a998178be C++: another shot at implicit/deleted copy 2022-03-10 13:17:18 -05:00
Robert Marsh
8efc13b378 C++: Update test comment and results 2022-03-03 15:00:50 -05:00
Robert Marsh
fa25f681e9 C++: change note for implicit copy improvements 2022-03-03 14:56:41 -05:00
Robert Marsh
440c9bfb4d C++: simplify implicitCopyConstructorDeleted 2022-03-01 15:23:56 -05:00
Robert Marsh
56caa5dfd6 C++: fix hasImplicitCopyConstructor for templates
Fixes some cases in instantiations of templates with manually written
copy constructors or copy assignment operators where
hasImplicitCopyConstructor would incorrectly hold
2022-02-07 14:26:28 -05:00
Robert Marsh
61c315d74b C++: test for explicit template copy constructor 2022-02-07 12:56:59 -05:00
Arthur Baars
6acf49d4da Merge pull request #7814 from aibaars/fix-ql-alerts
Ruby: fix all QL-QL alerts
2022-02-02 18:25:38 +01:00
Tony Torralba
4f13bf8941 Merge pull request #6492 from atorralba/atorralba/android-cleartext-storage-database
Java: Create new query Cleartext storage of sensitive information in Android databases
2022-02-02 16:23:05 +01:00
Tony Torralba
54e8ea56e8 Apply suggestions from code review
Co-authored-by: Anders Schack-Mulligen <aschackmull@users.noreply.github.com>
2022-02-02 15:44:26 +01:00
Mathias Vorreiter Pedersen
1aa32b09be Merge pull request #7802 from geoffw0/clrtxt8
C++: Recognize password struct fields.
2022-02-02 14:10:40 +00:00
Arthur Baars
3b05cb621c Address comment 2022-02-02 14:11:45 +01:00
Arthur Baars
33b97f3e0c Update synchronized files 2022-02-02 13:30:45 +01:00
Arthur Baars
fdcef6225b Ruby: fix QL warnings 2022-02-02 13:29:09 +01:00
CodeQL CI
7bb11b837c Merge pull request #7788 from yoff/python/remove-library-annotation
Approved by tausbn
2022-02-02 03:51:00 -08:00
Tom Hvitved
712418e5f8 Merge pull request #7781 from hvitved/dataflow/summary-stack-bottom-less-nonlinear
Data flow: Reduce non-linear recursion in `SummaryComponentStack::bottom`
2022-02-02 10:35:53 +01:00
Benjamin Muskalla
d4c4e75bac Merge pull request #7268 from bmuskalla/modelDiffAction
Java: Produce diffs for model generator changes
2022-02-02 10:30:45 +01:00
Henry Mercer
e622e517d9 Merge pull request #7800 from github/henrymercer/js-atm-add-model-building-pack
JS: Add model building pack for ML-powered queries
2022-02-01 20:51:19 +00:00
Geoffrey White
d864af3622 C++: Change note. 2022-02-01 19:00:40 +00:00
Harry Maclean
fb00a6c61b Merge pull request #7666 from github/hmac/file-open-access
Ruby: Add File.open as a FileSystemAccess
2022-02-02 07:32:16 +13:00
Henry Mercer
14601316a5 JS: Autoformat 2022-02-01 17:08:21 +00:00
Henry Mercer
368839edfc JS: Fix QLDoc style in ExtractMisclassifiedEndpointFeatures.ql 2022-02-01 15:39:15 +00:00
Arthur Baars
ea901adb3c Merge pull request #7799 from github/aibaars/fix-ruby-workflows
Ruby: use ruby specific cache key
2022-02-01 16:28:14 +01:00
Henry Mercer
db0b4fc463 JS: Add model building pack for ML-powered queries
Tests are currently still internal. They will be migrated to
`github/codeql` in a subsequent PR.
2022-02-01 15:03:26 +00:00
Arthur Baars
73d60550ce QL-QL: fix cache keys 2022-02-01 15:57:59 +01:00
Erik Krogh Kristensen
0f85a52f09 Merge pull request #7773 from erik-krogh/CWE-367
JS: add a js/file-system-race query
2022-02-01 15:36:13 +01:00
Arthur Baars
6451a71a78 Ruby: use ruby specific cache key 2022-02-01 15:18:09 +01:00
Mathias Vorreiter Pedersen
3597d80340 Merge pull request #7787 from Yonah125/main
C/C++ : Useless test
2022-02-01 14:01:27 +00:00
Nick Rolfe
5828a61fec Merge pull request #7795 from github/nickrolfe/graph_test_edge_ordering
Ruby/C#: add semmle.order attribute to edges in CFG tests
2022-02-01 13:36:15 +00:00
Erik Krogh Kristensen
a51f892a99 move dot in qhelp
Co-authored-by: Esben Sparre Andreasen <esbena@github.com>
2022-02-01 14:34:30 +01:00
Erik Krogh Kristensen
e6c90670e6 Merge pull request #7740 from erik-krogh/CWE-347
JS: promote the js/jwt-missing-verification query out of experimental
2022-02-01 13:10:35 +01:00
Rasmus Wriedt Larsen
f7a0b17ed6 Merge pull request #7687 from yoff/python/PathInjection-FlowState
python: Rewrite path injection query to use flow state
2022-02-01 11:33:37 +01:00
Mathias Vorreiter Pedersen
a59a9ba82b C++: Autoformat. 2022-02-01 08:28:53 +00:00
yoff
8df04c58e9 Merge pull request #7793 from tausbn/python-fix-bad-TPythonTuple-join-order
Python: Fix bad join order in `TPythonTuple`
2022-01-31 22:39:58 +01:00
Harry Maclean
e5b7478028 Merge pull request #7780 from github/hmac/split-tests
Ruby: Split up CI jobs
2022-02-01 09:10:01 +13:00
Nick Rolfe
990e07b986 Ruby/C#: add semmle.order attribute to edges in CFG tests 2022-01-31 20:08:24 +00:00
BACK Yonah
46c1744204 C/C++: getFullyConverted replaced by getConversion* 2022-01-31 18:51:18 +01:00
Taus
4a29095e3b Python: Fix bad join order in TPythonTuple
TL;DR: Something introduced the following bad join order:
```
(227s) Tuple counts for dom#TObject::TPythonTuple#ff/2@i2#8f58670w after 3m46s:
25000      ~0%     {2} r1 = SCAN PointsToContext::PointsToContext::appliesToScope_dispred#ff#prev_delta OUTPUT In.1, In.0 'context'
24000      ~1%     {2} r2 = JOIN r1 WITH @py_scope#f ON FIRST 1 OUTPUT Lhs.1 'context', Lhs.0
1076876712 ~6%     {3} r3 = JOIN r2 WITH Flow::TupleNode#class#f CARTESIAN PRODUCT OUTPUT Rhs.0, Lhs.0 'context', Lhs.1
870129666  ~0%     {3} r4 = JOIN r3 WITH Flow::ControlFlowNode::isLoad_dispred#f ON FIRST 1 OUTPUT Lhs.1 'context', Lhs.2, Lhs.0 'origin'
870129000  ~0%     {3} r5 = r4 AND NOT dom#TObject::TPythonTuple#ff#prev(Lhs.2 'origin', Lhs.0 'context')
870129000  ~1%     {3} r6 = SCAN r5 OUTPUT In.2 'origin', In.1, In.0 'context'
9000       ~0%     {2} r7 = JOIN r6 WITH Flow::ControlFlowNode::getScope_dispred#ff ON FIRST 2 OUTPUT Lhs.0 'origin', Lhs.2 'context'
                    return r7
```
(...the above being the tuple counts _at the point when I cancelled the
query_!)

Rewriting the code to force a join between `TupleNode#class` and
`getScope` results in the following join orders:

```
(0s) Tuple counts for TObject::scope_loads_tuplenode#ff/2@b3cf0bo5 after 13ms:
37369 ~3%     {1} r1 = JOIN Flow::TupleNode#class#f WITH Flow::ControlFlowNode::isLoad_dispred#f ON FIRST 1 OUTPUT Lhs.0 'origin'
37369 ~3%     {2} r2 = JOIN r1 WITH Flow::ControlFlowNode::getScope_dispred#ff ON FIRST 1 OUTPUT Rhs.1 's', Lhs.0 'origin'
            return r2
```
and
```
(78s) Tuple counts for dom#TObject::TPythonTuple#ff/2@i53#121c440w after 6ms:
34736 ~3%     {2} r1 = SCAN PointsToContext::PointsToContext::appliesToScope_dispred#ff#prev_delta OUTPUT In.1, In.0 'context'
7370  ~5%     {2} r2 = JOIN r1 WITH TObject::scope_loads_tuplenode#ff ON FIRST 1 OUTPUT Lhs.1 'context', Rhs.1 'origin'
7370  ~5%     {2} r3 = r2 AND NOT dom#TObject::TPythonTuple#ff#prev(Lhs.1 'origin', Lhs.0 'context')
7370  ~1%     {2} r4 = SCAN r3 OUTPUT In.1 'origin', In.0 'context'
            return r4
```
the latter being the largest iteration of `dom#TPythonTuple` throughout
the log.

No other major performance issues were observed.
2022-01-31 16:59:50 +00:00
BACK Yonah
56941dba6b C/C++ : Fixed select issue in Useless Test 2022-01-31 16:56:12 +01:00
BACK Yonah
ca2ff6f9fb C/C++: Fixing minor issues in Useless Test query 2022-01-31 16:04:56 +01:00
Tom Hvitved
5503abc73d Merge pull request #7772 from hvitved/csharp/event-accessor-event-null
C#: Guard against `AssociatedSymbol` not being an `IEventSymbol`
2022-01-31 14:52:02 +01:00
Michael Nebel
56ac99039f Merge pull request #7720 from michaelnebel/csharp/extended-prop-patterns
C#: Desugar property patterns that uses member access syntax.
2022-01-31 13:24:24 +01:00
Erik Krogh Kristensen
8dcec2e037 apply suggestions from doc review
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2022-01-31 13:17:26 +01:00
Erik Krogh Kristensen
ec1a8cc826 apply suggestions from doc review
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2022-01-31 12:32:12 +01:00
Tom Hvitved
2354281721 C#: Add DB down/upgrade scripts 2022-01-31 11:46:10 +01:00
Tom Hvitved
32e58add7b C#: Extend compiler_generated to include event accessors 2022-01-31 11:45:23 +01:00
Rasmus Lerchedahl Petersen
211345c010 python: remove more annotations 2022-01-31 11:20:59 +01:00
Michael Nebel
7cbeffc8a7 C#: Refactor and use new language features. 2022-01-31 09:24:31 +01:00
Rasmus Lerchedahl Petersen
cac3862659 python: remove library annotation
to clean up QL warnings.
Should put these in a private module instead?
2022-01-31 08:50:37 +01:00
Rasmus Lerchedahl Petersen
0c3bce1415 python: deprecation
I am slightly concerned that the test now generates many more
intermediate results. I suppose that maes the analysis heavy.
Should the new library get a new name instead, so the old code
does not get evaluated?
2022-01-31 08:32:24 +01:00
BACK Yonah
d7313f3a82 C/C++ : Useless test 2022-01-30 14:33:32 +01:00
Mathias Vorreiter Pedersen
bb2feda8fb Merge pull request #7703 from geoffw0/getslocal 2022-01-28 19:35:15 +00:00
Geoffrey White
8a1b49f816 C++: Recognize password struct fields. 2022-01-28 19:10:46 +00:00
Mathias Vorreiter Pedersen
0f239e315c Merge pull request #7782 from geoffw0/clrtxt7
C++: Fix FPs for cpp/cleartext-storage-file
2022-01-28 17:24:05 +00:00
Geoffrey White
0396a84c3c C++: Remove empty predicate / extends. 2022-01-28 17:11:38 +00:00
Geoffrey White
af09dd8af1 C++: Fixes to gets models. 2022-01-28 16:04:23 +00:00
Geoffrey White
036e1495b8 Merge branch 'main' into getslocal 2022-01-28 15:58:13 +00:00
Geoffrey White
a695f02af4 C++: Add change note. 2022-01-28 12:38:27 +00:00
Tom Hvitved
82cceb0a29 C#: Mark event accessors without bodies as compiler generated 2022-01-28 13:11:34 +01:00
Tom Hvitved
682163962a Data flow: Sync files 2022-01-28 13:01:24 +01:00
Tom Hvitved
4bf07825a1 Data flow: Reduce non-linear recursion in SummaryComponentStack::bottom
Before:
```
[2022-01-28 09:45:34] (449s) Tuple counts for FlowSummaryImpl::Public::SummaryComponentStack::bottom_dispred#ff/2@i23#25a5eew4 after 432ms:
                      0       ~0%     {2} r1 = SCAN FlowSummaryImpl::Public::SummaryComponentStack::length#ff#prev_delta OUTPUT In.0 'this', (In.1 - 1)
                      0       ~0%     {2} r2 = JOIN r1 WITH FlowSummaryImpl::Public::SummaryComponentStack::drop#fff#prev ON FIRST 2 OUTPUT Rhs.2, Lhs.0 'this'
                      0       ~0%     {2} r3 = JOIN r2 WITH FlowSummaryImpl::Public::SummaryComponentStack::head_dispred#ff#prev ON FIRST 1 OUTPUT Lhs.1 'this', Rhs.1 'result'

                      4171589 ~5%     {2} r4 = SCAN FlowSummaryImpl::Public::SummaryComponentStack::length#ff#prev OUTPUT In.0 'this', (In.1 - 1)
                      4171589 ~0%     {2} r5 = JOIN r4 WITH FlowSummaryImpl::Public::SummaryComponentStack::drop#fff#prev ON FIRST 2 OUTPUT Rhs.2, Lhs.0 'this'
                      0       ~0%     {2} r6 = JOIN r5 WITH FlowSummaryImpl::Public::SummaryComponentStack::head_dispred#ff#prev_delta ON FIRST 1 OUTPUT Lhs.1 'this', Rhs.1 'result'

                      62238   ~0%     {3} r7 = SCAN FlowSummaryImpl::Public::SummaryComponentStack::drop#fff#prev_delta OUTPUT In.2, In.0 'this', In.1
                      62238   ~8%     {3} r8 = JOIN r7 WITH FlowSummaryImpl::Public::SummaryComponentStack::head_dispred#ff#prev ON FIRST 1 OUTPUT Lhs.1 'this', Lhs.2, Rhs.1 'result'
                      62238   ~5%     {5} r9 = JOIN r8 WITH FlowSummaryImpl::Public::SummaryComponentStack::length#ff#prev ON FIRST 1 OUTPUT Lhs.0 'this', Lhs.1, Lhs.2 'result', Rhs.1, (Rhs.1 - 1)
                      10373   ~6%     {5} r10 = SELECT r9 ON In.4 = In.1
                      10373   ~0%     {2} r11 = SCAN r10 OUTPUT In.0 'this', In.2 'result'

                      10373   ~0%     {2} r12 = r6 UNION r11
                      10373   ~0%     {2} r13 = r3 UNION r12
                      10373   ~0%     {2} r14 = r13 AND NOT FlowSummaryImpl::Public::SummaryComponentStack::bottom_dispred#ff#prev(Lhs.0 'this', Lhs.1 'result')
                                      return r14
```

After:
```
[2022-01-28 09:52:48] (6s) Tuple counts for FlowSummaryImpl::Public::SummaryComponentStack::bottom#ff/2@i21#6243afwv after 5ms:
                      0     ~0%     {2} r1 = JOIN FlowSummaryImpl::Public::SummaryComponentStack::bottom#ff#prev_delta WITH FlowSummaryImpl::Private::TConsSummaryComponentStack#fff#reorder_1_0_2#prev ON FIRST 1 OUTPUT Lhs.1 'result', Rhs.2 'this'

                      10373 ~3%     {2} r2 = SCAN FlowSummaryImpl::Private::TConsSummaryComponentStack#fff#prev_delta OUTPUT In.1, In.2 'this'
                      10373 ~2%     {2} r3 = JOIN r2 WITH FlowSummaryImpl::Public::SummaryComponentStack::bottom#ff#prev ON FIRST 1 OUTPUT Rhs.1 'result', Lhs.1 'this'

                      10373 ~2%     {2} r4 = r1 UNION r3
                      10373 ~2%     {2} r5 = r4 AND NOT FlowSummaryImpl::Public::SummaryComponentStack::bottom#ff#prev(Lhs.1 'this', Lhs.0 'result')
                      10373 ~0%     {2} r6 = SCAN r5 OUTPUT In.1 'this', In.0 'result'
                                    return r6
```
2022-01-28 13:00:04 +01:00
Geoffrey White
b73dc98191 C++: Exclude write to stdout etc. 2022-01-28 11:57:31 +00:00
Tom Hvitved
864b61a804 Merge pull request #7766 from hvitved/csharp/extractor/type-param-constraints
C#: Make `TypeParameterConstraints` a `CachedEntity`
2022-01-28 12:39:31 +01:00
Tom Hvitved
28702dff82 Merge pull request #7779 from hvitved/csharp/initial-downgrade-scheme
C#: Add initial downgrade DB scheme for use in tests
2022-01-28 12:38:07 +01:00
Erik Krogh Kristensen
7b925604df update expected output 2022-01-28 12:21:33 +01:00
Nick Rolfe
588e60e230 Merge pull request #7775 from github/nickrolfe/graph_test_ordering
Ruby/C#: more stable graph test ordering
2022-01-28 11:16:02 +00:00
Erik Krogh Kristensen
7aa59ca233 Merge pull request #7633 from erik-krogh/CWE-300
JS: add js/http-dependency query
2022-01-28 12:10:14 +01:00
Taus
47a57e0c0a Merge pull request #7635 from github/python/support-match
Python/support match
2022-01-28 11:55:46 +01:00
yoff
74d57bbb1a Update python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
Co-authored-by: Taus <tausbn@github.com>
2022-01-28 11:38:29 +01:00
Erik Krogh Kristensen
b5198bdaca apply suggestions from doc review
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2022-01-28 10:46:27 +01:00
Erik Krogh Kristensen
bf9bcc9600 add a js/file-system-race query 2022-01-28 09:41:12 +01:00
Erik Krogh Kristensen
179c26da9a apply suggestions from review 2022-01-28 09:37:46 +01:00
Tony Torralba
f3e034b2be Merge pull request #7764 from github/workflow/coverage/update
Update CSV framework coverage reports
2022-01-28 09:35:54 +01:00
Harry Maclean
0428b8ee20 Split Ruby CI into multiple parallel jobs
Run format, compile and db upgrade checks in parallel, along with the
main tests, which run in two parallel halves.
2022-01-28 21:23:34 +13:00
Esben Sparre Andreasen
ee52774e90 Merge pull request #7760 from erik-krogh/CWE-184
JS: add CWE-184 to incomplete-scheme-check and bad-tag-filter
2022-01-28 09:18:41 +01:00
Tom Hvitved
ee5495ce65 C#: Add initial downgrade DB scheme for use in tests 2022-01-28 09:05:42 +01:00
github-actions[bot]
c6130ea2d4 Add changed framework coverage reports 2022-01-28 00:11:49 +00:00
Dave Bartolomeo
cca74e925f Merge pull request #7724 from github/aeisenberg/examples-groups
Add new groups for examples packs
2022-01-27 12:11:26 -05:00
Rasmus Lerchedahl Petersen
c60df7d69c Merge branch 'main' of github.com:github/codeql into python/support-match 2022-01-27 16:45:17 +01:00
yoff
4632c14280 Merge pull request #7654 from RasmusWL/remove-old-pointsto-queries
Python: Cleanup: Remove old points-to versions of queries
2022-01-27 16:39:01 +01:00
Nick Rolfe
cd5010fe11 C#: sync changes from Ruby to improve ordering of graph test output 2022-01-27 15:34:01 +00:00
Tom Hvitved
b7fb9e8b95 Merge pull request #7768 from hvitved/csharp/extractor-diagnostics-query
C#: Add internal extractor diagnostics query
2022-01-27 16:33:32 +01:00
Chris Smowton
17656fc12b Merge pull request #7771 from Dig2/main
Fix typo in CodeQL-query-help-for-JavaScript
2022-01-27 15:03:35 +00:00
Rasmus Lerchedahl Petersen
b93c04bb79 python: Add reverse flow in some patterns
Particularly in value and literal patterns.
This is getting a little bit into the guards aspect of matching.
We could similarly add reverse flow in terms of
sub-patterns storing to a sequence pattern,
a flow step from alternatives to an-or-pattern, etc..
It does not seem too likely that sources are embedded in patterns
to begin with, but for secrets perhaps?

It is illustrated by the literal test. The value test still fails.
I believe we miss flow in general from the static attribute.
2022-01-27 15:20:23 +01:00
Tom Hvitved
cdfe239016 C#: Guard against AssociatedSymbol not being an IEventSymbol
Apply same logic as for property/indexer accessors to account for cases where
the associated event cannot be determined. I have not been able to reproduce
such cases locally, though we have seen reports of it happening.
2022-01-27 15:14:03 +01:00
Nick Rolfe
6f06263d49 Ruby: add more properties for ordering nodes in graph tests 2022-01-27 13:57:43 +00:00
Dig2
516bed391a Fix CodeQL-query-help-for-JavaScript typo 2022-01-27 21:33:20 +08:00
Benjamin Muskalla
5c9c83d331 Revert "Enable on my repo"
This reverts commit b9c3e6a052.
2022-01-27 14:24:41 +01:00
Geoffrey White
47528dd8c0 C++: Autoformat. 2022-01-27 12:56:16 +00:00
Benjamin Muskalla
39a853b5e4 Remove unused models 2022-01-27 12:27:37 +01:00
Benjamin Muskalla
1cfb088634 rely on defaults 2022-01-27 12:26:59 +01:00
Benjamin Muskalla
e5acc6b54b use default sha for pr 2022-01-27 12:26:59 +01:00
Benjamin Muskalla
3646ae0995 Skip diff install if not needed 2022-01-27 12:26:58 +01:00
Benjamin Muskalla
10aa7a7982 Better name 2022-01-27 12:02:42 +01:00
Benjamin Muskalla
b9c3e6a052 Enable on my repo 2022-01-27 12:01:47 +01:00
Benjamin Muskalla
66b9974dd4 Simplify naming pattern 2022-01-27 12:00:29 +01:00
Benjamin Muskalla
4aa0002e97 Rename workflow 2022-01-27 11:43:25 +01:00
Tom Hvitved
e2ae327a74 C#: Add internal extractor diagnostics query 2022-01-27 11:19:31 +01:00
Rasmus Lerchedahl Petersen
cb52ab669e python: address review comments
The comment about `py_scopes` was simply removed
2022-01-27 11:17:00 +01:00
yoff
e28669e487 Apply suggestions from code review
Co-authored-by: Taus <tausbn@github.com>
2022-01-27 10:31:43 +01:00
Tom Hvitved
f4195219f4 C#: Make TypeParameterConstraints a CachedEntity 2022-01-27 10:19:16 +01:00
Andrew Eisenberg
a7f755cf12 Add new groups for examples packs
Also, remove version numbers. Will make it easier to avoid publishing
the examples packs.
2022-01-26 14:49:18 -08:00
Erik Krogh Kristensen
e75dc2116f add CWE-184 to incomplete-scheme-check and bad-tag-filter 2022-01-26 16:13:13 +01:00
Rasmus Lerchedahl Petersen
47af3a69a5 Merge branch 'main' of github.com:github/codeql into python/support-match 2022-01-26 11:39:46 +01:00
Erik Krogh Kristensen
abd87615ff update qhelp with suggestions
Co-authored-by: Esben Sparre Andreasen <esbena@github.com>
2022-01-26 11:03:05 +01:00
Erik Krogh Kristensen
de633940fe promote the js/jwt-missing-verification query out of exeprimental 2022-01-26 09:35:54 +01:00
Michael Nebel
f1d5d3af9d C#: Add change note for extended property patterns. 2022-01-25 15:13:11 +01:00
Michael Nebel
44cc044a3d C#: Add testcase for extended property patterns (to indicate that they are de-sugared correctly). 2022-01-25 15:13:11 +01:00
Michael Nebel
833e8e4f1d C#: Add some examples with the extended property pattern syntax. 2022-01-25 15:13:11 +01:00
Michael Nebel
83e7fae578 C#: Desugar property patterns that uses member access syntax. 2022-01-25 15:13:11 +01:00
Tony Torralba
4f4f531dfc Add missing QLDoc 2022-01-24 15:13:09 +01:00
Geoffrey White
588447d596 C++: Fix up isParameterDeref. 2022-01-24 11:06:24 +00:00
Geoffrey White
4326e6f706 C++: Split 'gets' model and make it a local source. 2022-01-21 17:29:49 +00:00
Geoffrey White
79735f5ac5 C++: Add test case. 2022-01-21 17:29:48 +00:00
Tony Torralba
4df0f399cd Move ContentProvider models to the appropriate file 2022-01-21 16:55:43 +01:00
Tony Torralba
c6dd7ddf7a Fix stub 2022-01-21 16:55:43 +01:00
Tony Torralba
4f253590f1 Fix method name in LocalDatabaseOpenMethodAccess 2022-01-21 16:55:43 +01:00
Tony Torralba
652a1d2dc2 Fix wrongly resolved rebase conflicts 2022-01-21 16:55:43 +01:00
Tony Torralba
5cf664411b Remove unneeded nonSuspicious values 2022-01-21 16:55:43 +01:00
Tony Torralba
baa1f71a53 Add QLDoc 2022-01-21 16:55:43 +01:00
Tony Torralba
4e4f619ae4 Update java/ql/lib/semmle/code/java/security/CleartextStorageAndroidDatabaseQuery.qll
Co-authored-by: Chris Smowton <smowton@github.com>
2022-01-21 16:55:43 +01:00
Tony Torralba
c5ed5fcaac Apply suggestions from code review
Co-authored-by: Ethan Palm <56270045+ethanpalm@users.noreply.github.com>
2022-01-21 16:55:42 +01:00
Tony Torralba
ee84dae164 Fix predicate name 2022-01-21 16:55:42 +01:00
Tony Torralba
16b61f78e6 Fix QLDocs and the qhelp example 2022-01-21 16:55:42 +01:00
Tony Torralba
f0604e2e84 Added query for Cleartext Storage in Android Database 2022-01-21 16:55:42 +01:00
Rasmus Lerchedahl Petersen
9aa4c4a6a7 python: Add missing input
also update test expectation
2022-01-21 13:55:33 +01:00
Rasmus Lerchedahl Petersen
41908cbf9f python: add missing qldoc 2022-01-21 13:55:08 +01:00
Rasmus Lerchedahl Petersen
49d4b1480d python: Do not remove ChainedConfigs12.qll
since it was clearly already used.
Add deprecation message instead.
2022-01-21 12:27:29 +01:00
Rasmus Lerchedahl Petersen
35c9307baa python: rewrite NoSQLInjection to use flow state
This allows a bit more precision. Specifically, we could
 require the sanitizer to only affect `ConvertedToDict`.
 In practice, most sanitizers woudl probably fail on raw
 input also, though.
2022-01-21 12:12:58 +01:00
Erik Krogh Kristensen
debebb2b8c rewrite the qhelp for js/insecure-dependency 2022-01-21 10:41:08 +01:00
Rasmus Lerchedahl Petersen
a5bc5373d0 python: Rewrite path injection to use flow state
This removes the FP cause by chaining
This PR also removes `ChainedConfigs12.qll`,
as we hope to solve future problems via flow states.
2022-01-21 09:26:48 +01:00
Harry Maclean
5dcee6ba27 Ruby: Add File.open as a FileSystemAccess 2022-01-20 21:09:41 +13:00
Rasmus Lerchedahl Petersen
32cbeae05f python: missing start tag for relation 2022-01-20 08:56:12 +01:00
Rasmus Lerchedahl Petersen
d10ad3bdd4 python: update stats for tables 2022-01-20 08:42:32 +01:00
Rasmus Lerchedahl Petersen
7e9a9e3d9a python: remove compiler warnings 2022-01-19 18:01:58 +01:00
Rasmus Lerchedahl Petersen
a0e79c1d7a update stats for types
- should still update stats for tables
2022-01-19 16:38:19 +01:00
Rasmus Wriedt Larsen
93b3cd669a Python: Cleanup: Remove old points-to versions of queries
Since we've internally agreed that we've reached the same or better set
of results.
2022-01-19 15:30:12 +01:00
Rasmus Lerchedahl Petersen
db253e8939 python: upgrade and downgrade scripts 2022-01-19 15:22:57 +01:00
Rasmus Lerchedahl Petersen
ef9fb0873f python: tools for writing upgrades and downgrade
adapted from [the ruby instructions](https://github.com/github/codeql/blob/main/ruby/doc/prepare-db-upgrade.md)
2022-01-19 14:29:58 +01:00
Rasmus Lerchedahl Petersen
36e18d5d80 python: dataflow for match
- also update `validTest.py`, but commented out for now
  otherwise CI will fail until we force it to run with Python 3.10
- added debug utility for dataflow (`dataflowTestPaths.ql`)
2022-01-19 14:29:58 +01:00
Rasmus Lerchedahl Petersen
bb210f4172 pythos: SSA for match
- new SSA definition `PatternCaptureDefinition`
- new SSA definition `PatternAliasDefinition`
- implement `hasDefiningNode`
2022-01-19 14:29:58 +01:00
Rasmus Lerchedahl Petersen
de8ecb214f python: Wrappers for database classes
- new syntactic category `Pattern` (in `Patterns.qll`)
- subpatterns available on statments
- new statements `MatchStmt` and `Case`
  (`Match` would conflict with the shared ReDoS library)
- new expression `Guard`
- support for pattern lists
2022-01-19 14:29:58 +01:00
Rasmus Lerchedahl Petersen
b17f844f35 python: New generated files 2022-01-19 13:36:32 +01:00
Erik Krogh Kristensen
b7a0b8765e add js/http-dependency query 2022-01-19 10:05:39 +01:00
Benjamin Muskalla
426f3117d6 Clarify model names and escape variables 2022-01-11 15:58:21 +01:00
Benjamin Muskalla
49d2fbfb5f Fixed slug references and PR skips 2022-01-11 11:47:28 +01:00
Benjamin Muskalla
557cb0a09e Add job name 2021-12-06 11:42:03 +01:00
Benjamin Muskalla
657c576186 Skip diffs if same branch 2021-12-06 11:30:14 +01:00
Benjamin Muskalla
38debc0b64 Remove push trigger 2021-12-06 11:21:15 +01:00
Benjamin Muskalla
d181ee1701 Shorten workflow name
This will show up including the job name anyway
```
Models as Data / model-diff (apache/commons-codec)
```
2021-11-30 12:19:10 +01:00
Benjamin Muskalla
5e69eb491f Generate diff and archive results 2021-11-30 12:19:10 +01:00
Benjamin Muskalla
734422f384 Generate the models for each variant 2021-11-30 12:19:10 +01:00
Benjamin Muskalla
9672128699 Download database 2021-11-30 12:19:10 +01:00
Benjamin Muskalla
c0a3cd07a5 Add default projects 2021-11-30 12:19:09 +01:00
Benjamin Muskalla
881539c735 Add scaffolding for model diff job 2021-11-30 12:19:09 +01:00
244 changed files with 24641 additions and 7085 deletions

View File

@@ -6,6 +6,7 @@
"*/ql/examples/qlpack.yml",
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
"csharp/ql/campaigns/Solorigate/lib/qlpack.yml",
"csharp/ql/campaigns/Solorigate/src/qlpack.yml",

103
.github/workflows/mad_modelDiff.yml vendored Normal file
View File

@@ -0,0 +1,103 @@
name: Models as Data - Diff
on:
workflow_dispatch:
inputs:
projects:
description: "The projects to generate models for"
required: true
default: '["netty/netty"]'
pull_request:
branches:
- main
paths:
- "java/ql/src/utils/model-generator/**/*.*"
- ".github/workflows/mad_modelDiff.yml"
permissions:
contents: read
jobs:
model-diff:
name: Model Difference
runs-on: ubuntu-latest
if: github.repository == 'github/codeql'
strategy:
matrix:
slug: ${{fromJson(github.event.inputs.projects || '["apache/commons-codec", "apache/commons-io", "apache/commons-beanutils", "apache/commons-logging", "apache/commons-fileupload", "apache/commons-lang", "apache/commons-validator", "apache/commons-csv", "apache/dubbo"]' )}}
steps:
- name: Clone github/codeql from PR
uses: actions/checkout@v2
if: github.event.pull_request
with:
path: codeql-pr
- name: Clone github/codeql from main
uses: actions/checkout@v2
with:
path: codeql-main
ref: main
- uses: ./codeql-main/.github/actions/fetch-codeql
- name: Download database
env:
SLUG: ${{ matrix.slug }}
run: |
set -x
mkdir lib-dbs
SHORTNAME=${SLUG//[^a-zA-Z0-9_]/}
projectId=`curl -s https://lgtm.com/api/v1.0/projects/g/${SLUG} | jq .id`
curl -L "https://lgtm.com/api/v1.0/snapshots/$projectId/java" -o "$SHORTNAME.zip"
unzip -q -d "${SHORTNAME}-db" "${SHORTNAME}.zip"
mkdir "lib-dbs/$SHORTNAME/"
mv "${SHORTNAME}-db/"$(ls -1 "${SHORTNAME}"-db)/* "lib-dbs/${SHORTNAME}/"
- name: Generate Models (PR and main)
run: |
set -x
mkdir tmp-models
MODELS=`pwd`/tmp-models
DATABASES=`pwd`/lib-dbs
analyzeDatabaseWithCheckout() {
QL_VARIANT=$1
DATABASE=$2
cd codeql-$QL_VARIANT
SHORTNAME=`basename $DATABASE`
python java/ql/src/utils/model-generator/GenerateFlowModel.py $DATABASE $MODELS/${SHORTNAME}.qll
mv $MODELS/${SHORTNAME}.qll $MODELS/${SHORTNAME}Generated_${QL_VARIANT}.qll
cd ..
}
for d in $DATABASES/*/ ; do
ls -1 "$d"
analyzeDatabaseWithCheckout "main" $d
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]
then
analyzeDatabaseWithCheckout "pr" $d
fi
done
- name: Install diff2html
if: github.event.pull_request
run: |
npm install -g diff2html-cli
- name: Generate Model Diff
if: github.event.pull_request
run: |
set -x
MODELS=`pwd`/tmp-models
ls -1 tmp-models/
for m in $MODELS/*_main.qll ; do
t="${m/main/"pr"}"
basename=`basename $m`
name="diff_${basename/_main.qll/""}"
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
done
- uses: actions/upload-artifact@v2
with:
name: models
path: tmp-models/*.qll
retention-days: 20
- uses: actions/upload-artifact@v2
with:
name: diffs
path: tmp-models/*.html
retention-days: 20

View File

@@ -17,7 +17,7 @@ jobs:
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
strategy:
matrix:
repo:
repo:
- github/codeql
- github/codeql-go
runs-on: ubuntu-latest
@@ -35,7 +35,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
ql/target
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Build Extractor
run: cd ql; env "PATH=$PATH:`dirname ${CODEQL}`" ./create-extractor-pack.sh
env:

View File

@@ -29,24 +29,24 @@ jobs:
~/.cargo/registry
~/.cargo/git
ql/target
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Build extractor
run: |
cd ql;
codeqlpath=$(dirname ${{ steps.find-codeql.outputs.codeql-path }});
env "PATH=$PATH:$codeqlpath" ./create-extractor-pack.sh
- name: Run QL tests
run: |
run: |
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries ql/ql/test
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL formatting
run: |
run: |
find ql/ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL compilation
run: |
run: |
"${CODEQL}" query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ql/extractor-pack" "ql/ql/src" "ql/ql/examples"
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}

View File

@@ -50,7 +50,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
ruby/target
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-ruby-rust-cargo-${{ hashFiles('ruby/**/Cargo.lock') }}
- name: Check formatting
run: cargo fmt --all -- --check
- name: Build

View File

@@ -24,27 +24,45 @@ defaults:
working-directory: ruby
jobs:
qltest:
qlformat:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- uses: ./ruby/actions/create-extractor-pack
- name: Run QL tests
run: |
codeql test run --threads=0 --ram 5000 --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check QL formatting
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
qlcompile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- name: Check QL compilation
run: |
codeql query compile --check-only --threads=0 --ram 5000 --warnings=error "ql/src" "ql/examples"
env:
GITHUB_TOKEN: ${{ github.token }}
qlupgrade:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- name: Check DB upgrade scripts
run: |
echo >empty.trap
codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
codeql dataset upgrade testdb --additional-packs ql/lib
diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme
qltest:
runs-on: ubuntu-latest
strategy:
matrix:
slice: ["1/2", "2/2"]
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- uses: ./ruby/actions/create-extractor-pack
- name: Run QL tests
run: |
codeql test run --threads=0 --ram 5000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
env:
GITHUB_TOKEN: ${{ github.token }}

View File

@@ -1,4 +1,6 @@
name: codeql/cpp-examples
version: 0.0.2
groups:
- cpp
- examples
dependencies:
codeql/cpp-all: "*"

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `Class::hasImplicitCopyConstructor` and `Class::hasImplicitCopyAssignmentOperator` methods now handle template instantiations more accurately. This should improve results for the `cpp/rule-of-two` query.

View File

@@ -285,7 +285,17 @@ class Class extends UserType {
predicate hasImplicitCopyConstructor() {
not this.implicitCopyConstructorDeleted() and
forall(CopyConstructor cc | cc = this.getAMemberFunction() |
cc.isCompilerGenerated() and not cc.isDeleted()
cc.isCompilerGenerated() and not cc.isDeleted() and not cc.isDefaulted()
) and
(
not this instanceof ClassTemplateInstantiation
or
this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyConstructor()
) and
(
not this instanceof PartialClassTemplateSpecialization
or
this.(PartialClassTemplateSpecialization).getPrimaryTemplate().hasImplicitCopyConstructor()
)
}
@@ -300,7 +310,19 @@ class Class extends UserType {
predicate hasImplicitCopyAssignmentOperator() {
not this.implicitCopyAssignmentOperatorDeleted() and
forall(CopyAssignmentOperator ca | ca = this.getAMemberFunction() |
ca.isCompilerGenerated() and not ca.isDeleted()
ca.isCompilerGenerated() and not ca.isDeleted() and not ca.isDefaulted()
) and
(
not this instanceof ClassTemplateInstantiation
or
this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyAssignmentOperator()
) and
(
not this instanceof PartialClassTemplateSpecialization
or
this.(PartialClassTemplateSpecialization)
.getPrimaryTemplate()
.hasImplicitCopyAssignmentOperator()
)
}
@@ -311,6 +333,12 @@ class Class extends UserType {
* http://en.cppreference.com/w/cpp/language/copy_constructor#Deleted_implicitly-declared_copy_constructor
*/
predicate implicitCopyConstructorDeleted() {
forex(CopyConstructor cc | cc = this.getAConstructor() |
cc.isDeleted()
or
not cc.isCompilerGenerated()
)
or
// - T has non-static data members that cannot be copied (have deleted,
// inaccessible, or ambiguous copy constructors);
exists(Type t | t = this.getAFieldSubobjectType().getUnspecifiedType() |
@@ -318,34 +346,6 @@ class Class extends UserType {
// constructors are considered equal.
this.cannotAccessCopyConstructorOnAny(t)
)
or
// - T has direct or virtual base class that cannot be copied (has deleted,
// inaccessible, or ambiguous copy constructors);
exists(Class c | c = this.getADirectOrVirtualBase() |
// Note: Overload resolution is not implemented -- all copy
// constructors are considered equal.
this.cannotAccessCopyConstructorOnThis(c)
)
or
// - T has direct or virtual base class with a deleted or inaccessible
// destructor;
exists(Class base | base = this.getADirectOrVirtualBase() |
this.cannotAccessDestructor(base, this)
)
or
// - T has a user-defined move constructor or move assignment operator;
exists(MoveConstructor mc | mc = this.getAMemberFunction() | not mc.isCompilerGenerated())
or
exists(MoveAssignmentOperator ma | ma = this.getAMemberFunction() |
not ma.isCompilerGenerated()
)
or
// - T is a union and has a variant member with non-trivial copy
// constructor (since C++11)
none() // Not implemented
or
// - T has a data member of rvalue reference type.
exists(Type t | t = this.getAFieldSubobjectType() | t instanceof RValueReferenceType)
}
/**
@@ -355,34 +355,12 @@ class Class extends UserType {
* http://en.cppreference.com/w/cpp/language/copy_assignment#Deleted_implicitly-declared_copy_assignment_operator
*/
predicate implicitCopyAssignmentOperatorDeleted() {
// - T has a user-declared move constructor;
exists(MoveConstructor mc | mc = this.getAMemberFunction() | not mc.isCompilerGenerated())
or
// - T has a user-declared move assignment operator.
exists(MoveAssignmentOperator ma | ma = this.getAMemberFunction() |
not ma.isCompilerGenerated()
forex(CopyAssignmentOperator ca | ca = this.getAMemberFunction() |
ca.isDeleted()
or
not ca.isCompilerGenerated()
)
or
// - T has a non-static data member of non-class type (or array thereof)
// that is const;
exists(Type t | t = this.getAFieldSubobjectType() |
// The rule for this case refers only to non-class types only, but our
// implementation extends it to cover class types too. Class types are
// supposed to be covered by the rule below on data members that
// cannot be copy-assigned. Copy-assigning a const class-typed member
// would call an overload of type
// `const C& operator=(const C&) const;`. Such an overload is unlikely
// to exist because it contradicts the intention of "const": it allows
// assigning to a const object. But since we have not implemented the
// ability to distinguish between overloads, we cannot distinguish that
// overload from the ordinary `C& operator=(const C&);`. Instead, we
// require class types to be non-const in this clause.
/* not t instanceof Class and */ t.isConst()
)
or
// - T has a non-static data member of a reference type;
exists(Type t | t = this.getAFieldSubobjectType() | t instanceof ReferenceType)
or
// - T has a non-static data member or a direct or virtual base class that
// cannot be copy-assigned (overload resolution for the copy assignment
// fails, or selects a deleted or inaccessible function);
@@ -391,15 +369,6 @@ class Class extends UserType {
// operators are considered equal.
this.cannotAccessCopyAssignmentOperatorOnAny(t)
)
or
exists(Class c | c = this.getADirectOrVirtualBase() |
// Note: Overload resolution is not implemented -- all copy assignment
// operators are considered equal.
this.cannotAccessCopyAssignmentOperatorOnThis(c)
)
// - T is a union-like class, and has a variant member whose corresponding
// assignment operator is non-trivial.
// Not implemented
}
/** Gets the destructor of this class, struct or union, if any. */

View File

@@ -1290,7 +1290,7 @@ class DataFlowCallOption extends TDataFlowCallOption {
}
}
/** Content tagged with the type of a containing object. */
/** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;
private DataFlowType t;

View File

@@ -1290,7 +1290,7 @@ class DataFlowCallOption extends TDataFlowCallOption {
}
}
/** Content tagged with the type of a containing object. */
/** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;
private DataFlowType t;

View File

@@ -11,15 +11,14 @@ import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.FlowSource
/**
* The standard functions `gets` and `fgets`.
* The standard functions `fgets` and `fgetws`.
*/
private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction,
private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction,
SideEffectFunction, RemoteFlowSourceFunction {
GetsFunction() {
// gets(str)
FgetsFunction() {
// fgets(str, num, stream)
// fgetws(wstr, num, stream)
this.hasGlobalOrStdOrBslName(["gets", "fgets", "fgetws"])
this.hasGlobalOrStdOrBslName(["fgets", "fgetws"])
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
@@ -51,20 +50,61 @@ private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunctio
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
output.isParameterDeref(0) and
description = "String read by " + this.getName()
or
output.isReturnValue() and
description = "String read by " + this.getName()
}
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
not this.hasName("gets") and
bufParam = 0 and
countParam = 1
}
override predicate hasArrayWithUnknownSize(int bufParam) {
this.hasName("gets") and
bufParam = 0
}
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
override predicate hasSocketInput(FunctionInput input) { input.isParameter(2) }
override predicate hasSocketInput(FunctionInput input) { input.isParameterDeref(2) }
}
/**
* The standard functions `gets`.
*/
private class GetsFunction extends DataFlowFunction, ArrayFunction, AliasFunction,
SideEffectFunction, LocalFlowSourceFunction {
GetsFunction() {
// gets(str)
this.hasGlobalOrStdOrBslName("gets")
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isParameter(0) and
output.isReturnValue()
}
override predicate parameterNeverEscapes(int index) { none() }
override predicate parameterEscapesOnlyViaReturn(int index) { index = 0 }
override predicate parameterIsAlwaysReturned(int index) { index = 0 }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and
buffer = true and
mustWrite = true
}
override predicate hasLocalFlowSource(FunctionOutput output, string description) {
output.isParameterDeref(0) and
description = "String read by " + this.getName()
or
output.isReturnValue() and
description = "String read by " + this.getName()
}
override predicate hasArrayWithUnknownSize(int bufParam) { bufParam = 0 }
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
}

View File

@@ -6,122 +6,22 @@
*/
class Person extends string {
Person() {
this = "Ronil" or
this = "Dina" or
this = "Ravi" or
this = "Bruce" or
this = "Jo" or
this = "Aida" or
this = "Esme" or
this = "Charlie" or
this = "Fred" or
this = "Meera" or
this = "Maya" or
this = "Chad" or
this = "Tiana" or
this = "Laura" or
this = "George" or
this = "Will" or
this = "Mary" or
this = "Almira" or
this = "Susannah" or
this = "Rhoda" or
this = "Cynthia" or
this = "Eunice" or
this = "Olive" or
this = "Virginia" or
this = "Angeline" or
this = "Helen" or
this = "Cornelia" or
this = "Harriet" or
this = "Mahala" or
this = "Abby" or
this = "Margaret" or
this = "Deb" or
this = "Minerva" or
this = "Severus" or
this = "Lavina" or
this = "Adeline" or
this = "Cath" or
this = "Elisa" or
this = "Lucretia" or
this = "Anne" or
this = "Eleanor" or
this = "Joanna" or
this = "Adam" or
this = "Agnes" or
this = "Rosanna" or
this = "Clara" or
this = "Melissa" or
this = "Amy" or
this = "Isabel" or
this = "Jemima" or
this = "Cordelia" or
this = "Melinda" or
this = "Delila" or
this = "Jeremiah" or
this = "Elijah" or
this = "Hester" or
this = "Walter" or
this = "Oliver" or
this = "Hugh" or
this = "Aaron" or
this = "Reuben" or
this = "Eli" or
this = "Amos" or
this = "Augustus" or
this = "Theodore" or
this = "Ira" or
this = "Timothy" or
this = "Cyrus" or
this = "Horace" or
this = "Simon" or
this = "Asa" or
this = "Frank" or
this = "Nelson" or
this = "Leonard" or
this = "Harrison" or
this = "Anthony" or
this = "Louis" or
this = "Milton" or
this = "Noah" or
this = "Cornelius" or
this = "Abdul" or
this = "Warren" or
this = "Harvey" or
this = "Dennis" or
this = "Wesley" or
this = "Sylvester" or
this = "Gilbert" or
this = "Sullivan" or
this = "Edmund" or
this = "Wilson" or
this = "Perry" or
this = "Matthew" or
this = "Simba" or
this = "Nala" or
this = "Rafiki" or
this = "Shenzi" or
this = "Ernest" or
this = "Gertrude" or
this = "Oscar" or
this = "Lilian" or
this = "Raymond" or
this = "Elgar" or
this = "Elmer" or
this = "Herbert" or
this = "Maude" or
this = "Mae" or
this = "Otto" or
this = "Edwin" or
this = "Ophelia" or
this = "Parsley" or
this = "Sage" or
this = "Rosemary" or
this = "Thyme" or
this = "Garfunkel" or
this = "King Basil" or
this = "Stephen"
this =
[
"Ronil", "Dina", "Ravi", "Bruce", "Jo", "Aida", "Esme", "Charlie", "Fred", "Meera", "Maya",
"Chad", "Tiana", "Laura", "George", "Will", "Mary", "Almira", "Susannah", "Rhoda",
"Cynthia", "Eunice", "Olive", "Virginia", "Angeline", "Helen", "Cornelia", "Harriet",
"Mahala", "Abby", "Margaret", "Deb", "Minerva", "Severus", "Lavina", "Adeline", "Cath",
"Elisa", "Lucretia", "Anne", "Eleanor", "Joanna", "Adam", "Agnes", "Rosanna", "Clara",
"Melissa", "Amy", "Isabel", "Jemima", "Cordelia", "Melinda", "Delila", "Jeremiah", "Elijah",
"Hester", "Walter", "Oliver", "Hugh", "Aaron", "Reuben", "Eli", "Amos", "Augustus",
"Theodore", "Ira", "Timothy", "Cyrus", "Horace", "Simon", "Asa", "Frank", "Nelson",
"Leonard", "Harrison", "Anthony", "Louis", "Milton", "Noah", "Cornelius", "Abdul", "Warren",
"Harvey", "Dennis", "Wesley", "Sylvester", "Gilbert", "Sullivan", "Edmund", "Wilson",
"Perry", "Matthew", "Simba", "Nala", "Rafiki", "Shenzi", "Ernest", "Gertrude", "Oscar",
"Lilian", "Raymond", "Elgar", "Elmer", "Herbert", "Maude", "Mae", "Otto", "Edwin",
"Ophelia", "Parsley", "Sage", "Rosemary", "Thyme", "Garfunkel", "King Basil", "Stephen"
]
}
/** Gets the hair color of the person. If the person is bald, there is no result. */
@@ -936,25 +836,12 @@ class Person extends string {
/** Holds if the person is deceased. */
predicate isDeceased() {
this = "Ernest" or
this = "Gertrude" or
this = "Oscar" or
this = "Lilian" or
this = "Edwin" or
this = "Raymond" or
this = "Elgar" or
this = "Elmer" or
this = "Herbert" or
this = "Maude" or
this = "Mae" or
this = "Otto" or
this = "Ophelia" or
this = "Parsley" or
this = "Sage" or
this = "Rosemary" or
this = "Thyme" or
this = "Garfunkel" or
this = "King Basil"
this =
[
"Ernest", "Gertrude", "Oscar", "Lilian", "Edwin", "Raymond", "Elgar", "Elmer", "Herbert",
"Maude", "Mae", "Otto", "Ophelia", "Parsley", "Sage", "Rosemary", "Thyme", "Garfunkel",
"King Basil"
]
}
/** Gets a parent of the person (alive or deceased). */
@@ -1195,12 +1082,7 @@ class Person extends string {
}
/** Holds if the person is allowed in the region. Initially, all villagers are allowed in every region. */
predicate isAllowedIn(string region) {
region = "north" or
region = "south" or
region = "east" or
region = "west"
}
predicate isAllowedIn(string region) { region = ["north", "south", "east", "west"] }
}
/** Returns a parent of the person. */

View File

@@ -65,6 +65,7 @@ where
midNode.getNode().asExpr() = mid and
mid = w.getASource() and
dest = w.getDest() and
not dest.(VariableAccess).getTarget().getName() = ["stdin", "stdout", "stderr"] and // exclude calls with standard streams
not isFileName(globalValueNumber(source)) and // file names are not passwords
not exists(string convChar | convChar = w.getSourceConvChar(mid) | not convChar = ["s", "S"]) // ignore things written with other conversion characters
select w, sourceNode, midNode,

View File

@@ -27,6 +27,7 @@ class SensitiveNode extends DataFlow::Node {
this.asExpr() = any(SensitiveVariable sv).getInitializer().getExpr() or
this.asExpr().(VariableAccess).getTarget() =
any(SensitiveVariable sv).(GlobalOrNamespaceVariable) or
this.asExpr().(VariableAccess).getTarget() = any(SensitiveVariable v | v instanceof Field) or
this.asUninitialized() instanceof SensitiveVariable or
this.asParameter() instanceof SensitiveVariable or
this.asExpr().(FunctionCall).getTarget() instanceof SensitiveFunction
@@ -58,7 +59,10 @@ class Send extends SendRecv instanceof RemoteFlowSinkFunction {
call.getTarget() = this and
exists(FunctionInput input, int arg |
super.hasSocketInput(input) and
input.isParameter(arg) and
(
input.isParameter(arg) or
input.isParameterDeref(arg)
) and
result = call.getArgument(arg)
)
}
@@ -81,7 +85,10 @@ class Recv extends SendRecv instanceof RemoteFlowSourceFunction {
call.getTarget() = this and
exists(FunctionInput input, int arg |
super.hasSocketInput(input) and
input.isParameter(arg) and
(
input.isParameter(arg) or
input.isParameterDeref(arg)
) and
result = call.getArgument(arg)
)
}

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The "Cleartext transmission of sensitive information" (`cpp/cleartext-transmission`) query now finds more results, where a password is stored in a struct field or class member variable.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `cpp/cleartext-storage-file` query has been improved, removing false positives where data is written to a standard output stream.

View File

@@ -0,0 +1,9 @@
void test(){
int a = 8;
int b = 9;
//Useless NonEquals
if(a==8 && a != 7) {}
while(a==8 && a!=7){}
}

View File

@@ -0,0 +1,18 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Comparison operations like <code>a==8 &amp;&amp; a!=7</code> contain a useless part : the non-equal part. This rule finds tests of this kind within an <code>if</code> or a <code>while</code> statement</p>
</overview>
<recommendation>
<p>Remove the useless comparisons</p>
</recommendation>
<example>
<sample src="UselessTest.cpp" />
</example>
</qhelp>

View File

@@ -0,0 +1,43 @@
/**
* @name Useless Test
* @description A boolean condition that is guaranteed to never be evaluated should be deleted.
* @kind problem
* @problem.severity warning
* @id cpp/uselesstest
* @tags reliability
* readability
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
predicate sameExpr(Expr e1, Expr e2) { globalValueNumber(e1).getAnExpr() = e2 }
Element nearestParent(Expr e) {
if
e.getParent().(Expr).getConversion*() instanceof ParenthesisExpr or
e.getParent() instanceof IfStmt or
e.getParent() instanceof WhileStmt
then result = e.getParent()
else result = nearestParent(e.getParent())
}
from LogicalAndExpr b, EQExpr eq, NEExpr ne
where
(
b.getAChild*() = eq and
b.getAChild*() = ne and
eq.getParent() instanceof LogicalAndExpr and
ne.getParent() instanceof LogicalAndExpr
) and
(
eq.getLeftOperand() instanceof VariableAccess and ne.getLeftOperand() instanceof VariableAccess
or
eq.getLeftOperand() instanceof PointerDereferenceExpr and
ne.getLeftOperand() instanceof PointerDereferenceExpr
) and
eq.getRightOperand() instanceof Literal and
ne.getRightOperand() instanceof Literal and
nearestParent(eq) = nearestParent(ne) and
sameExpr(eq.getLeftOperand(), ne.getLeftOperand())
select ne, "Useless Test"

View File

@@ -1,6 +1,8 @@
name: codeql/cpp-queries
version: 0.0.8-dev
groups: cpp
groups:
- cpp
- queries
dependencies:
codeql/cpp-all: "*"
codeql/suite-helpers: "*"

View File

@@ -93,7 +93,7 @@
private import InlineExpectationsTestPrivate
/**
* Base class for tests with inline expectations. The test extends this class to provide the actual
* The base class for tests with inline expectations. The test extends this class to provide the actual
* results of the query, which are then compared with the expected results in comments to produce a
* list of failure messages that point out where the actual results differ from the expected
* results.

View File

@@ -11,6 +11,7 @@
| difference::Base | can | does NOT | have implicit copy assignment |
| difference::OnlyAssign | can | does | have implicit copy assignment |
| difference::OnlyCtor | can NOT | does NOT | have implicit copy assignment |
| instantiated_explicit_ctor::Wrapper<int> | can | does | have implicit copy assignment |
| moves::MoveAssign | can NOT | does NOT | have implicit copy assignment |
| moves::MoveCtor | can NOT | does NOT | have implicit copy assignment |
| private_cc::C | can | does NOT | have implicit copy assignment |

View File

@@ -131,3 +131,21 @@ namespace difference {
class OnlyAssign : Base {
};
}
namespace instantiated_explicit_ctor {
template<class T>
class Wrapper {
public:
Wrapper(Wrapper<T> &other) {
m_t = other.m_t;
}
Wrapper() {
m_t = 0;
}
private:
T m_t;
};
Wrapper<int> wrapped_int;
}

View File

@@ -11,6 +11,7 @@
| difference::Base | can | does NOT | have implicit copy constructor |
| difference::OnlyAssign | can NOT | does NOT | have implicit copy constructor |
| difference::OnlyCtor | can | does | have implicit copy constructor |
| instantiated_explicit_ctor::Wrapper<int> | can | does NOT | have implicit copy constructor |
| moves::MoveAssign | can NOT | does NOT | have implicit copy constructor |
| moves::MoveCtor | can NOT | does NOT | have implicit copy constructor |
| private_cc::C | can | does NOT | have implicit copy constructor |

View File

@@ -86,5 +86,9 @@
| copy.cpp:131:9:131:9 | OnlyAssign | deleted | |
| copy.cpp:131:9:131:9 | operator= | | |
| copy.cpp:131:9:131:9 | operator= | | |
| copy.cpp:137:9:137:9 | operator= | | |
| copy.cpp:139:5:139:11 | Wrapper | | |
| copy.cpp:143:5:143:5 | Wrapper | | |
| copy.cpp:143:5:143:11 | Wrapper | | |
| file://:0:0:0:0 | operator= | | |
| file://:0:0:0:0 | operator= | | |

View File

@@ -117,12 +117,8 @@ struct HasVPV {
}
};
// FALSE NEGATIVE: the relevant copy constructor of ProtectedVolatile is
// accessible, so our class will get a generated copy constructor. Our query
// thinks the copy constructor is inaccessible because it picks up the other
// copy constructor. To fix this, our library should be changed to distinguish
// between copy constructors and resolve overloading properly instead of
// assuming that there is at most one.
// NOT OK: the relevant copy constructor of ProtectedVolatile is
// accessible, so our class will get a generated copy constructor.
struct HasPV {
ProtectedVolatile pv;
HasPV& operator=(const HasPV& that) {

View File

@@ -1,6 +1,6 @@
| RuleOfTwo.cpp:4:3:4:17 | CopyButNoAssign | No matching copy assignment operator in class CopyButNoAssign. It is good practice to match a copy constructor with a copy assignment operator. |
| RuleOfTwo.cpp:10:20:10:28 | operator= | No matching copy constructor in class AssignButNoCopy. It is good practice to match a copy assignment operator with a copy constructor. |
| RuleOfTwo.cpp:81:18:81:26 | operator= | No matching copy constructor in class MyClassFriend. It is good practice to match a copy assignment operator with a copy constructor. |
| RuleOfTwo.cpp:144:3:144:20 | IsAProtectedAssign | No matching copy assignment operator in class IsAProtectedAssign. It is good practice to match a copy constructor with a copy assignment operator. |
| RuleOfTwo.cpp:167:19:167:27 | operator= | No matching copy constructor in class IsAProtectedCC. It is good practice to match a copy assignment operator with a copy constructor. |
| RuleOfTwo.cpp:312:5:312:8 | R1_C | No matching copy assignment operator in class R1_C. It is good practice to match a copy constructor with a copy assignment operator. |
| RuleOfTwo.cpp:140:3:140:20 | IsAProtectedAssign | No matching copy assignment operator in class IsAProtectedAssign. It is good practice to match a copy constructor with a copy assignment operator. |
| RuleOfTwo.cpp:163:19:163:27 | operator= | No matching copy constructor in class IsAProtectedCC. It is good practice to match a copy assignment operator with a copy constructor. |
| RuleOfTwo.cpp:308:5:308:8 | R1_C | No matching copy assignment operator in class R1_C. It is good practice to match a copy constructor with a copy assignment operator. |

View File

@@ -1,8 +1,10 @@
edges
| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input |
nodes
| test2.cpp:110:3:110:6 | call to gets | semmle.label | call to gets |
| test.cpp:54:17:54:20 | argv | semmle.label | argv |
| test.cpp:58:25:58:29 | input | semmle.label | input |
subpaths
#select
| test2.cpp:110:3:110:6 | call to gets | test2.cpp:110:3:110:6 | call to gets | test2.cpp:110:3:110:6 | call to gets | This write into buffer 'password' may contain unencrypted data from $@ | test2.cpp:110:3:110:6 | call to gets | user input (String read by gets) |
| test.cpp:58:3:58:9 | call to sprintf | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | This write into buffer 'passwd' may contain unencrypted data from $@ | test.cpp:54:17:54:20 | argv | user input (a command-line argument) |

View File

@@ -1,4 +1,5 @@
edges
| test2.cpp:63:24:63:31 | password | test2.cpp:63:16:63:20 | call to crypt |
| test3.cpp:17:28:17:36 | password1 | test3.cpp:22:15:22:23 | password1 |
| test3.cpp:17:51:17:59 | password2 | test3.cpp:26:15:26:23 | password2 |
| test3.cpp:45:8:45:15 | password | test3.cpp:47:15:47:22 | password |
@@ -89,11 +90,15 @@ edges
| test3.cpp:398:18:398:25 | password | test3.cpp:400:15:400:23 | & ... |
| test3.cpp:398:18:398:25 | password | test3.cpp:400:16:400:23 | password |
| test3.cpp:398:18:398:25 | password | test3.cpp:400:33:400:40 | password |
| test3.cpp:421:21:421:28 | password | test3.cpp:421:3:421:17 | call to decrypt_inplace |
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:21:48:27 | call to encrypt |
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:29:48:39 | thePassword |
| test.cpp:66:23:66:43 | cleartext password! | test.cpp:76:21:76:27 | call to encrypt |
| test.cpp:66:23:66:43 | cleartext password! | test.cpp:76:29:76:39 | thePassword |
nodes
| test2.cpp:63:16:63:20 | call to crypt | semmle.label | call to crypt |
| test2.cpp:63:24:63:31 | password | semmle.label | password |
| test2.cpp:63:24:63:31 | password | semmle.label | password |
| test3.cpp:17:28:17:36 | password1 | semmle.label | password1 |
| test3.cpp:17:51:17:59 | password2 | semmle.label | password2 |
| test3.cpp:22:15:22:23 | password1 | semmle.label | password1 |
@@ -208,6 +213,11 @@ nodes
| test3.cpp:400:15:400:23 | & ... | semmle.label | & ... |
| test3.cpp:400:16:400:23 | password | semmle.label | password |
| test3.cpp:400:33:400:40 | password | semmle.label | password |
| test3.cpp:414:17:414:24 | password | semmle.label | password |
| test3.cpp:420:17:420:24 | password | semmle.label | password |
| test3.cpp:421:3:421:17 | call to decrypt_inplace | semmle.label | call to decrypt_inplace |
| test3.cpp:421:21:421:28 | password | semmle.label | password |
| test3.cpp:421:21:421:28 | password | semmle.label | password |
| test.cpp:41:23:41:43 | cleartext password! | semmle.label | cleartext password! |
| test.cpp:48:21:48:27 | call to encrypt | semmle.label | call to encrypt |
| test.cpp:48:29:48:39 | thePassword | semmle.label | thePassword |
@@ -238,3 +248,5 @@ subpaths
| test3.cpp:300:2:300:5 | call to send | test3.cpp:308:58:308:66 | password2 | test3.cpp:300:14:300:17 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:308:58:308:66 | password2 | password2 |
| test3.cpp:341:4:341:7 | call to recv | test3.cpp:339:9:339:16 | password | test3.cpp:341:16:341:23 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:339:9:339:16 | password | password |
| test3.cpp:388:3:388:6 | call to recv | test3.cpp:386:8:386:15 | password | test3.cpp:388:15:388:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:386:8:386:15 | password | password |
| test3.cpp:414:3:414:6 | call to recv | test3.cpp:414:17:414:24 | password | test3.cpp:414:17:414:24 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:414:17:414:24 | password | password |
| test3.cpp:420:3:420:6 | call to recv | test3.cpp:420:17:420:24 | password | test3.cpp:420:17:420:24 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:420:17:420:24 | password | password |

View File

@@ -99,3 +99,14 @@ void tests(FILE *log, myStruct &s)
fprintf(log, "log: %s", buffer); // BAD
}
}
char *gets(char *s);
void test_gets()
{
{
char password[1024];
gets(password); // BAD
}
}

View File

@@ -411,13 +411,13 @@ void test_member_password()
{
packet p;
recv(val(), p.password, 256, val()); // BAD: not encrypted [NOT DETECTED]
recv(val(), p.password, 256, val()); // BAD: not encrypted
}
{
packet p;
recv(val(), p.password, 256, val()); // GOOD: password is encrypted
recv(val(), p.password, 256, val()); // GOOD: password is encrypted [FALSE POSITIVE]
decrypt_inplace(p.password); // proof that `password` was in fact encrypted
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support for compiler-generated event accessors.
compatibility: backwards

File diff suppressed because it is too large Load Diff

View File

@@ -6,11 +6,15 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class Accessor : Method
{
protected Accessor(Context cx, IMethodSymbol init)
: base(cx, init) { }
private readonly IPropertySymbol property;
protected Accessor(Context cx, IMethodSymbol init, IPropertySymbol property)
: base(cx, init)
{
this.property = property;
}
/// <summary>
/// Gets the property symbol associated accessor `symbol`, or `null`
/// Gets the property symbol associated with accessor `symbol`, or `null`
/// if there is no associated symbol.
/// </summary>
public static IPropertySymbol? GetPropertySymbol(IMethodSymbol symbol)
@@ -26,39 +30,26 @@ namespace Semmle.Extraction.CSharp.Entities
return props.SingleOrDefault();
}
/// <summary>
/// Gets the property symbol associated with this accessor.
/// </summary>
private IPropertySymbol? PropertySymbol => GetPropertySymbol(Symbol);
public new Accessor OriginalDefinition => Create(Context, Symbol.OriginalDefinition);
public override void Populate(TextWriter trapFile)
{
PopulateMethod(trapFile);
PopulateModifiers(trapFile);
ContainingType!.PopulateGenerics();
var prop = PropertySymbol;
if (prop is null)
{
var type = Symbol.AssociatedSymbol?.GetType().ToString() ?? "null";
Context.ModelError(Symbol, $"Unhandled accessor associated symbol of type {type}");
return;
}
var parent = Property.Create(Context, prop);
var parent = Property.Create(Context, property);
int kind;
Accessor unboundAccessor;
if (SymbolEqualityComparer.Default.Equals(Symbol, prop.GetMethod))
if (SymbolEqualityComparer.Default.Equals(Symbol, property.GetMethod))
{
kind = 1;
unboundAccessor = Create(Context, prop.OriginalDefinition.GetMethod!);
var orig = property.OriginalDefinition;
unboundAccessor = Create(Context, orig.GetMethod!, orig);
}
else if (SymbolEqualityComparer.Default.Equals(Symbol, prop.SetMethod))
else if (SymbolEqualityComparer.Default.Equals(Symbol, property.SetMethod))
{
kind = 2;
unboundAccessor = Create(Context, prop.OriginalDefinition.SetMethod!);
var orig = property.OriginalDefinition;
unboundAccessor = Create(Context, orig.SetMethod!, orig);
}
else
{
@@ -84,14 +75,14 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public static new Accessor Create(Context cx, IMethodSymbol symbol) =>
AccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
public static Accessor Create(Context cx, IMethodSymbol symbol, IPropertySymbol prop) =>
AccessorFactory.Instance.CreateEntity(cx, symbol, (symbol, prop));
private class AccessorFactory : CachedEntityFactory<IMethodSymbol, Accessor>
private class AccessorFactory : CachedEntityFactory<(IMethodSymbol, IPropertySymbol), Accessor>
{
public static AccessorFactory Instance { get; } = new AccessorFactory();
public override Accessor Create(Context cx, IMethodSymbol init) => new Accessor(cx, init);
public override Accessor Create(Context cx, (IMethodSymbol, IPropertySymbol) init) => new(cx, init.Item1, init.Item2);
}
}
}

View File

@@ -3,45 +3,46 @@ using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class EventAccessor : Accessor
internal class EventAccessor : Method
{
private EventAccessor(Context cx, IMethodSymbol init)
: base(cx, init) { }
private readonly IEventSymbol @event;
private EventAccessor(Context cx, IMethodSymbol init, IEventSymbol @event)
: base(cx, init)
{
this.@event = @event;
}
/// <summary>
/// Gets the event symbol associated with this accessor.
/// Gets the event symbol associated with accessor `symbol`, or `null`
/// if there is no associated symbol.
/// </summary>
private IEventSymbol? EventSymbol => Symbol.AssociatedSymbol as IEventSymbol;
public static IEventSymbol? GetEventSymbol(IMethodSymbol symbol) =>
symbol.AssociatedSymbol as IEventSymbol;
public override void Populate(TextWriter trapFile)
{
PopulateMethod(trapFile);
ContainingType!.PopulateGenerics();
var @event = EventSymbol;
if (@event is null)
{
var type = Symbol.AssociatedSymbol?.GetType().ToString() ?? "null";
Context.ModelError(Symbol, $"Unhandled event accessor associated symbol of type {type}");
return;
}
var parent = Event.Create(Context, @event);
int kind;
EventAccessor unboundAccessor;
if (SymbolEqualityComparer.Default.Equals(Symbol, @event.AddMethod))
{
kind = 1;
unboundAccessor = Create(Context, @event.OriginalDefinition.AddMethod!);
var orig = @event.OriginalDefinition;
unboundAccessor = Create(Context, orig.AddMethod!, orig);
}
else if (SymbolEqualityComparer.Default.Equals(Symbol, @event.RemoveMethod))
{
kind = 2;
unboundAccessor = Create(Context, @event.OriginalDefinition.RemoveMethod!);
var orig = @event.OriginalDefinition;
unboundAccessor = Create(Context, orig.RemoveMethod!, orig);
}
else
{
Context.ModelError(Symbol, "Undhandled event accessor kind");
Context.ModelError(Symbol, $"Undhandled event accessor kind {Symbol.ToDisplayString()}");
return;
}
@@ -51,16 +52,21 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.event_accessor_location(this, l);
Overrides(trapFile);
if (Symbol.FromSource() && Block is null)
{
trapFile.compiler_generated(this);
}
}
public static new EventAccessor Create(Context cx, IMethodSymbol symbol) =>
EventAccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
public static EventAccessor Create(Context cx, IMethodSymbol symbol, IEventSymbol @event) =>
EventAccessorFactory.Instance.CreateEntity(cx, symbol, (symbol, @event));
private class EventAccessorFactory : CachedEntityFactory<IMethodSymbol, EventAccessor>
private class EventAccessorFactory : CachedEntityFactory<(IMethodSymbol, IEventSymbol), EventAccessor>
{
public static EventAccessorFactory Instance { get; } = new EventAccessorFactory();
public override EventAccessor Create(Context cx, IMethodSymbol init) => new EventAccessor(cx, init);
public override EventAccessor Create(Context cx, (IMethodSymbol, IEventSymbol) init) => new EventAccessor(cx, init.Item1, init.Item2);
}
}
}

View File

@@ -1,3 +1,5 @@
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Kinds;
using Semmle.Extraction.Entities;
@@ -10,17 +12,69 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
base(new ExpressionInfo(cx, null, cx.CreateLocation(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null))
{
child = 0;
var trapFile = cx.TrapWriter.Writer;
foreach (var sub in pp.Subpatterns)
{
var p = Expressions.Pattern.Create(cx, sub.Pattern, this, child++);
if (sub.NameColon is null)
if (sub.ExpressionColon is null)
{
Context.ModelError(sub, "Expected to find 'Name:' in pattern.");
Context.ModelError(sub, "Expected to find 'Expression:' in pattern.");
continue;
}
trapFile.exprorstmt_name(p, sub.NameColon.Name.ToString());
MakeExpressions(cx, this, sub, child++);
}
}
private record AccessStep(string Identifier, Microsoft.CodeAnalysis.Location Location);
private class AccessStepPack
{
public readonly List<AccessStep> Prefix = new List<AccessStep>();
public AccessStep Last { get; private set; }
public AccessStepPack Add(string identifier, Microsoft.CodeAnalysis.Location location)
{
Prefix.Add(Last);
Last = new AccessStep(identifier, location);
return this;
}
public AccessStepPack(string identifier, Microsoft.CodeAnalysis.Location location) =>
Last = new AccessStep(identifier, location);
}
private static AccessStepPack GetAccessStepPack(ExpressionSyntax syntax) =>
syntax switch
{
MemberAccessExpressionSyntax memberAccess => GetAccessStepPack(memberAccess.Expression).Add(memberAccess.Name.Identifier.ValueText, memberAccess.Name.Identifier.GetLocation()),
IdentifierNameSyntax identifier => new AccessStepPack(identifier.Identifier.Text, identifier.GetLocation()),
_ => throw new InternalError(syntax, "Unexpected expression syntax in property patterns."),
};
private static AccessStepPack GetAccessStepPack(BaseExpressionColonSyntax syntax) =>
syntax switch
{
NameColonSyntax ncs => new AccessStepPack(ncs.Name.ToString(), ncs.Name.GetLocation()),
ExpressionColonSyntax ecs => GetAccessStepPack(ecs.Expression),
_ => throw new InternalError(syntax, "Unsupported expression colon in property pattern."),
};
private static Expression CreateSyntheticExp(Context cx, Microsoft.CodeAnalysis.Location location, IExpressionParentEntity parent, int child) =>
new Expression(new ExpressionInfo(cx, null, cx.CreateLocation(location), ExprKind.PROPERTY_PATTERN, parent, child, false, null));
private static void MakeExpressions(Context cx, IExpressionParentEntity parent, SubpatternSyntax syntax, int child)
{
var trapFile = cx.TrapWriter.Writer;
var pack = GetAccessStepPack(syntax.ExpressionColon!);
foreach (var step in pack.Prefix)
{
var exp = CreateSyntheticExp(cx, step.Location, parent, child);
trapFile.exprorstmt_name(exp, step.Identifier);
parent = exp;
child = 0;
}
var p = Expressions.Pattern.Create(cx, syntax.Pattern, parent, child);
trapFile.exprorstmt_name(p, pack.Last.Identifier);
}
}
}

View File

@@ -262,10 +262,10 @@ namespace Semmle.Extraction.CSharp.Entities
return Destructor.Create(cx, methodDecl);
case MethodKind.PropertyGet:
case MethodKind.PropertySet:
return Accessor.GetPropertySymbol(methodDecl) is null ? OrdinaryMethod.Create(cx, methodDecl) : (Method)Accessor.Create(cx, methodDecl);
return Accessor.GetPropertySymbol(methodDecl) is IPropertySymbol prop ? Accessor.Create(cx, methodDecl, prop) : OrdinaryMethod.Create(cx, methodDecl);
case MethodKind.EventAdd:
case MethodKind.EventRemove:
return EventAccessor.Create(cx, methodDecl);
return EventAccessor.GetEventSymbol(methodDecl) is IEventSymbol @event ? EventAccessor.Create(cx, methodDecl, @event) : OrdinaryMethod.Create(cx, methodDecl);
case MethodKind.UserDefinedOperator:
case MethodKind.BuiltinOperator:
return UserOperator.Create(cx, methodDecl);

View File

@@ -1,7 +1,5 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Entities;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -21,34 +19,10 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
var constraints = new TypeParameterConstraints(Context);
trapFile.type_parameter_constraints(constraints, this);
if (Symbol.HasReferenceTypeConstraint)
trapFile.general_type_parameter_constraints(constraints, 1);
if (Symbol.HasValueTypeConstraint)
trapFile.general_type_parameter_constraints(constraints, 2);
if (Symbol.HasConstructorConstraint)
trapFile.general_type_parameter_constraints(constraints, 3);
if (Symbol.HasUnmanagedTypeConstraint)
trapFile.general_type_parameter_constraints(constraints, 4);
if (Symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated)
trapFile.general_type_parameter_constraints(constraints, 5);
foreach (var abase in Symbol.GetAnnotatedTypeConstraints())
{
var t = Create(Context, abase.Symbol);
trapFile.specific_type_parameter_constraints(constraints, t.TypeRef);
if (!abase.HasObliviousNullability())
trapFile.specific_type_parameter_nullability(constraints, t.TypeRef, NullabilityEntity.Create(Context, Nullability.Create(abase)));
}
trapFile.types(this, Kinds.TypeKind.TYPE_PARAMETER, Symbol.Name);
TypeParameterConstraints.Create(Context, this);
var parentNs = Namespace.Create(Context, Symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : Symbol.ContainingNamespace);
trapFile.parent_namespace(this, parentNs);

View File

@@ -1,14 +1,65 @@
using Microsoft.CodeAnalysis;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class TypeParameterConstraints : FreshEntity
internal class TypeParameterConstraints : CachedEntity<ITypeParameterSymbol>
{
public TypeParameterConstraints(Context cx)
: base(cx) { }
private readonly TypeParameter parent;
protected override void Populate(TextWriter trapFile)
public TypeParameterConstraints(Context cx, TypeParameter parent)
: base(cx, parent.Symbol)
{
this.parent = parent;
}
public override void WriteId(EscapingTextWriter trapFile)
{
trapFile.WriteSubId(parent);
trapFile.Write(";typeparameterconstraints");
}
public override bool NeedsPopulation => true;
public override void Populate(TextWriter trapFile)
{
trapFile.type_parameter_constraints(this, parent);
if (Symbol.HasReferenceTypeConstraint)
trapFile.general_type_parameter_constraints(this, 1);
if (Symbol.HasValueTypeConstraint)
trapFile.general_type_parameter_constraints(this, 2);
if (Symbol.HasConstructorConstraint)
trapFile.general_type_parameter_constraints(this, 3);
if (Symbol.HasUnmanagedTypeConstraint)
trapFile.general_type_parameter_constraints(this, 4);
if (Symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated)
trapFile.general_type_parameter_constraints(this, 5);
foreach (var abase in Symbol.GetAnnotatedTypeConstraints())
{
var t = Type.Create(Context, abase.Symbol);
trapFile.specific_type_parameter_constraints(this, t.TypeRef);
if (!abase.HasObliviousNullability())
trapFile.specific_type_parameter_nullability(this, t.TypeRef, NullabilityEntity.Create(Context, Nullability.Create(abase)));
}
}
public override Location? ReportingLocation => null;
public static TypeParameterConstraints Create(Context cx, TypeParameter p) =>
TypeParameterConstraintsFactory.Instance.CreateEntity(cx, (typeof(TypeParameterConstraints), p), p);
private class TypeParameterConstraintsFactory : CachedEntityFactory<TypeParameter, TypeParameterConstraints>
{
public static TypeParameterConstraintsFactory Instance { get; } = new TypeParameterConstraintsFactory();
public override TypeParameterConstraints Create(Context cx, TypeParameter init) => new(cx, init);
}
}
}

View File

@@ -1,4 +1,6 @@
name: codeql/csharp-examples
version: 0.0.2
groups:
- csharp
- examples
dependencies:
codeql/csharp-all: "*"

View File

@@ -0,0 +1,4 @@
---
category: majorAnalysis
---
* Added support for C# 10 [Extended property patterns](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10#extended-property-patterns).

View File

@@ -214,7 +214,7 @@ abstract class SplitKind extends SplitKindBase {
abstract string toString();
}
/** Provides the interface for implementing an entity to split on. */
/** An interface for implementing an entity to split on. */
abstract class SplitImpl extends Split {
/** Gets the kind of this split. */
abstract SplitKind getKind();
@@ -894,16 +894,31 @@ module TestOutput {
p
order by
l.getFile().getBaseName(), l.getFile().getAbsolutePath(), l.getStartLine(),
l.getStartColumn()
l.getStartColumn(), l.getEndLine(), l.getEndColumn(), p.toString()
)
).toString()
}
query predicate edges(RelevantNode pred, RelevantNode succ, string attr, string val) {
attr = "semmle.label" and
exists(SuccessorType t | succ = getASuccessor(pred, t) |
attr = "semmle.label" and
if successorTypeIsSimple(t) then val = "" else val = t.toString()
)
or
attr = "semmle.order" and
val =
any(int i |
succ =
rank[i](RelevantNode s, SuccessorType t, Location l |
s = getASuccessor(pred, t) and
l = s.getLocation()
|
s
order by
l.getFile().getBaseName(), l.getFile().getAbsolutePath(), l.getStartLine(),
l.getStartColumn(), l.getEndLine(), l.getEndColumn(), t.toString()
)
).toString()
}
}

View File

@@ -1290,7 +1290,7 @@ class DataFlowCallOption extends TDataFlowCallOption {
}
}
/** Content tagged with the type of a containing object. */
/** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;
private DataFlowType t;

View File

@@ -90,7 +90,9 @@ module Public {
predicate contains(SummaryComponent c) { c = this.drop(_).head() }
/** Gets the bottom element of this stack. */
SummaryComponent bottom() { result = this.drop(this.length() - 1).head() }
SummaryComponent bottom() {
this = TSingletonSummaryComponentStack(result) or result = this.tail().bottom()
}
/** Gets a textual representation of this stack. */
string toString() {

View File

@@ -648,7 +648,7 @@ has_modifiers(
int id: @modifiable_direct ref,
int mod_id: @modifier ref);
compiler_generated(unique int id: @modifiable_direct ref);
compiler_generated(unique int id: @modifiable ref);
/** MEMBERS **/

View File

@@ -6,122 +6,22 @@
*/
class Person extends string {
Person() {
this = "Ronil" or
this = "Dina" or
this = "Ravi" or
this = "Bruce" or
this = "Jo" or
this = "Aida" or
this = "Esme" or
this = "Charlie" or
this = "Fred" or
this = "Meera" or
this = "Maya" or
this = "Chad" or
this = "Tiana" or
this = "Laura" or
this = "George" or
this = "Will" or
this = "Mary" or
this = "Almira" or
this = "Susannah" or
this = "Rhoda" or
this = "Cynthia" or
this = "Eunice" or
this = "Olive" or
this = "Virginia" or
this = "Angeline" or
this = "Helen" or
this = "Cornelia" or
this = "Harriet" or
this = "Mahala" or
this = "Abby" or
this = "Margaret" or
this = "Deb" or
this = "Minerva" or
this = "Severus" or
this = "Lavina" or
this = "Adeline" or
this = "Cath" or
this = "Elisa" or
this = "Lucretia" or
this = "Anne" or
this = "Eleanor" or
this = "Joanna" or
this = "Adam" or
this = "Agnes" or
this = "Rosanna" or
this = "Clara" or
this = "Melissa" or
this = "Amy" or
this = "Isabel" or
this = "Jemima" or
this = "Cordelia" or
this = "Melinda" or
this = "Delila" or
this = "Jeremiah" or
this = "Elijah" or
this = "Hester" or
this = "Walter" or
this = "Oliver" or
this = "Hugh" or
this = "Aaron" or
this = "Reuben" or
this = "Eli" or
this = "Amos" or
this = "Augustus" or
this = "Theodore" or
this = "Ira" or
this = "Timothy" or
this = "Cyrus" or
this = "Horace" or
this = "Simon" or
this = "Asa" or
this = "Frank" or
this = "Nelson" or
this = "Leonard" or
this = "Harrison" or
this = "Anthony" or
this = "Louis" or
this = "Milton" or
this = "Noah" or
this = "Cornelius" or
this = "Abdul" or
this = "Warren" or
this = "Harvey" or
this = "Dennis" or
this = "Wesley" or
this = "Sylvester" or
this = "Gilbert" or
this = "Sullivan" or
this = "Edmund" or
this = "Wilson" or
this = "Perry" or
this = "Matthew" or
this = "Simba" or
this = "Nala" or
this = "Rafiki" or
this = "Shenzi" or
this = "Ernest" or
this = "Gertrude" or
this = "Oscar" or
this = "Lilian" or
this = "Raymond" or
this = "Elgar" or
this = "Elmer" or
this = "Herbert" or
this = "Maude" or
this = "Mae" or
this = "Otto" or
this = "Edwin" or
this = "Ophelia" or
this = "Parsley" or
this = "Sage" or
this = "Rosemary" or
this = "Thyme" or
this = "Garfunkel" or
this = "King Basil" or
this = "Stephen"
this =
[
"Ronil", "Dina", "Ravi", "Bruce", "Jo", "Aida", "Esme", "Charlie", "Fred", "Meera", "Maya",
"Chad", "Tiana", "Laura", "George", "Will", "Mary", "Almira", "Susannah", "Rhoda",
"Cynthia", "Eunice", "Olive", "Virginia", "Angeline", "Helen", "Cornelia", "Harriet",
"Mahala", "Abby", "Margaret", "Deb", "Minerva", "Severus", "Lavina", "Adeline", "Cath",
"Elisa", "Lucretia", "Anne", "Eleanor", "Joanna", "Adam", "Agnes", "Rosanna", "Clara",
"Melissa", "Amy", "Isabel", "Jemima", "Cordelia", "Melinda", "Delila", "Jeremiah", "Elijah",
"Hester", "Walter", "Oliver", "Hugh", "Aaron", "Reuben", "Eli", "Amos", "Augustus",
"Theodore", "Ira", "Timothy", "Cyrus", "Horace", "Simon", "Asa", "Frank", "Nelson",
"Leonard", "Harrison", "Anthony", "Louis", "Milton", "Noah", "Cornelius", "Abdul", "Warren",
"Harvey", "Dennis", "Wesley", "Sylvester", "Gilbert", "Sullivan", "Edmund", "Wilson",
"Perry", "Matthew", "Simba", "Nala", "Rafiki", "Shenzi", "Ernest", "Gertrude", "Oscar",
"Lilian", "Raymond", "Elgar", "Elmer", "Herbert", "Maude", "Mae", "Otto", "Edwin",
"Ophelia", "Parsley", "Sage", "Rosemary", "Thyme", "Garfunkel", "King Basil", "Stephen"
]
}
/** Gets the hair color of the person. If the person is bald, there is no result. */
@@ -936,25 +836,12 @@ class Person extends string {
/** Holds if the person is deceased. */
predicate isDeceased() {
this = "Ernest" or
this = "Gertrude" or
this = "Oscar" or
this = "Lilian" or
this = "Edwin" or
this = "Raymond" or
this = "Elgar" or
this = "Elmer" or
this = "Herbert" or
this = "Maude" or
this = "Mae" or
this = "Otto" or
this = "Ophelia" or
this = "Parsley" or
this = "Sage" or
this = "Rosemary" or
this = "Thyme" or
this = "Garfunkel" or
this = "King Basil"
this =
[
"Ernest", "Gertrude", "Oscar", "Lilian", "Edwin", "Raymond", "Elgar", "Elmer", "Herbert",
"Maude", "Mae", "Otto", "Ophelia", "Parsley", "Sage", "Rosemary", "Thyme", "Garfunkel",
"King Basil"
]
}
/** Gets a parent of the person (alive or deceased). */
@@ -1195,12 +1082,7 @@ class Person extends string {
}
/** Holds if the person is allowed in the region. Initially, all villagers are allowed in every region. */
predicate isAllowedIn(string region) {
region = "north" or
region = "south" or
region = "east" or
region = "west"
}
predicate isAllowedIn(string region) { region = ["north", "south", "east", "west"] }
}
/** Returns a parent of the person. */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support for compiler-generated event accessors.
compatibility: backwards

View File

@@ -0,0 +1,24 @@
/**
* @name Extractor diagnostics
* @description This query is for internal use only and may change without notice.
* @kind table
* @id csharp/extractor-diagnostics
*/
import csharp
bindingset[i]
private float getCompilationTimeSum(int i) {
result = sum(float f | compilation_time(_, _, i, f) | f)
}
select getCompilationTimeSum(0) as sum_frontend_cpu_seconds,
getCompilationTimeSum(1) as sum_frontend_elapsed_seconds,
getCompilationTimeSum(4) as sum_frontend_user_seconds,
getCompilationTimeSum(2) as sum_extractor_cpu_seconds,
getCompilationTimeSum(3) as sum_extractor_elapsed_seconds,
getCompilationTimeSum(5) as sum_extractor_user_seconds,
sum(float f | compilation_finished(_, f, _) | f) as sum_total_cpu_seconds,
sum(float f | compilation_finished(_, _, f) | f) as sum_total_elapsed_seconds,
getCompilationTimeSum(6) as sum_peak_working_set_mb,
max(float f | compilation_time(_, _, 6, f) | f) as max_peak_working_set_mb

View File

@@ -1,6 +1,8 @@
name: codeql/csharp-queries
version: 0.0.8-dev
groups: csharp
groups:
- csharp
- queries
suites: codeql-suites
extractor: csharp
defaultSuiteFile: codeql-suites/csharp-code-scanning.qls

View File

@@ -93,7 +93,7 @@
private import InlineExpectationsTestPrivate
/**
* Base class for tests with inline expectations. The test extends this class to provide the actual
* The base class for tests with inline expectations. The test extends this class to provide the actual
* results of the query, which are then compared with the expected results in comments to produce a
* list of failure messages that point out where the actual results differ from the expected
* results.

View File

@@ -0,0 +1,56 @@
using System;
public record Point(int X, int Y);
public record Line(Point P1, Point P2);
public record Wrap(Line L);
public class PropertyPatterns
{
private static Line l = new Line(new Point(1, 2), new Point(3, 6));
private static Wrap w = new Wrap(l);
public void M1()
{
if (l is { P1: { X: 1 } })
{
}
if (l is { P1.X: 2 })
{
}
}
public void M2()
{
if (w is { L: { P2: { Y: 3 } } })
{
}
if (w is { L.P2.Y: 4 })
{
}
}
public void M3()
{
if (w is { L: { P2.Y: 5 } })
{
}
if (w is { L.P2: { Y: 6 } })
{
}
}
public void M4()
{
if (l is { P1: { X: 7 }, P1: { Y: 8 } })
{
}
if (l is { P1.X: 9, P1.Y: 10 })
{
}
}
}

View File

@@ -0,0 +1,73 @@
propertyPatterns
| PropertyPatterns.cs:14:18:14:33 | { ... } |
| PropertyPatterns.cs:14:24:14:31 | { ... } |
| PropertyPatterns.cs:18:18:18:28 | { ... } |
| PropertyPatterns.cs:18:20:18:21 | { ... } |
| PropertyPatterns.cs:25:18:25:40 | { ... } |
| PropertyPatterns.cs:25:23:25:38 | { ... } |
| PropertyPatterns.cs:25:29:25:36 | { ... } |
| PropertyPatterns.cs:29:18:29:30 | { ... } |
| PropertyPatterns.cs:29:20:29:20 | { ... } |
| PropertyPatterns.cs:29:22:29:23 | { ... } |
| PropertyPatterns.cs:36:18:36:35 | { ... } |
| PropertyPatterns.cs:36:23:36:33 | { ... } |
| PropertyPatterns.cs:36:25:36:26 | { ... } |
| PropertyPatterns.cs:40:18:40:35 | { ... } |
| PropertyPatterns.cs:40:20:40:20 | { ... } |
| PropertyPatterns.cs:40:26:40:33 | { ... } |
| PropertyPatterns.cs:47:18:47:47 | { ... } |
| PropertyPatterns.cs:47:24:47:31 | { ... } |
| PropertyPatterns.cs:47:38:47:45 | { ... } |
| PropertyPatterns.cs:51:18:51:38 | { ... } |
| PropertyPatterns.cs:51:20:51:21 | { ... } |
| PropertyPatterns.cs:51:29:51:30 | { ... } |
propertyPatternChild
| PropertyPatterns.cs:14:18:14:33 | { ... } | 0 | PropertyPatterns.cs:14:24:14:31 | { ... } |
| PropertyPatterns.cs:14:24:14:31 | { ... } | 0 | PropertyPatterns.cs:14:29:14:29 | 1 |
| PropertyPatterns.cs:18:18:18:28 | { ... } | 0 | PropertyPatterns.cs:18:20:18:21 | { ... } |
| PropertyPatterns.cs:18:20:18:21 | { ... } | 0 | PropertyPatterns.cs:18:26:18:26 | 2 |
| PropertyPatterns.cs:25:18:25:40 | { ... } | 0 | PropertyPatterns.cs:25:23:25:38 | { ... } |
| PropertyPatterns.cs:25:23:25:38 | { ... } | 0 | PropertyPatterns.cs:25:29:25:36 | { ... } |
| PropertyPatterns.cs:25:29:25:36 | { ... } | 0 | PropertyPatterns.cs:25:34:25:34 | 3 |
| PropertyPatterns.cs:29:18:29:30 | { ... } | 0 | PropertyPatterns.cs:29:20:29:20 | { ... } |
| PropertyPatterns.cs:29:20:29:20 | { ... } | 0 | PropertyPatterns.cs:29:22:29:23 | { ... } |
| PropertyPatterns.cs:29:22:29:23 | { ... } | 0 | PropertyPatterns.cs:29:28:29:28 | 4 |
| PropertyPatterns.cs:36:18:36:35 | { ... } | 0 | PropertyPatterns.cs:36:23:36:33 | { ... } |
| PropertyPatterns.cs:36:23:36:33 | { ... } | 0 | PropertyPatterns.cs:36:25:36:26 | { ... } |
| PropertyPatterns.cs:36:25:36:26 | { ... } | 0 | PropertyPatterns.cs:36:31:36:31 | 5 |
| PropertyPatterns.cs:40:18:40:35 | { ... } | 0 | PropertyPatterns.cs:40:20:40:20 | { ... } |
| PropertyPatterns.cs:40:20:40:20 | { ... } | 0 | PropertyPatterns.cs:40:26:40:33 | { ... } |
| PropertyPatterns.cs:40:26:40:33 | { ... } | 0 | PropertyPatterns.cs:40:31:40:31 | 6 |
| PropertyPatterns.cs:47:18:47:47 | { ... } | 0 | PropertyPatterns.cs:47:24:47:31 | { ... } |
| PropertyPatterns.cs:47:18:47:47 | { ... } | 1 | PropertyPatterns.cs:47:38:47:45 | { ... } |
| PropertyPatterns.cs:47:24:47:31 | { ... } | 0 | PropertyPatterns.cs:47:29:47:29 | 7 |
| PropertyPatterns.cs:47:38:47:45 | { ... } | 0 | PropertyPatterns.cs:47:43:47:43 | 8 |
| PropertyPatterns.cs:51:18:51:38 | { ... } | 0 | PropertyPatterns.cs:51:20:51:21 | { ... } |
| PropertyPatterns.cs:51:18:51:38 | { ... } | 1 | PropertyPatterns.cs:51:29:51:30 | { ... } |
| PropertyPatterns.cs:51:20:51:21 | { ... } | 0 | PropertyPatterns.cs:51:26:51:26 | 9 |
| PropertyPatterns.cs:51:29:51:30 | { ... } | 0 | PropertyPatterns.cs:51:35:51:36 | 10 |
propertyPatternLabels
| PropertyPatterns.cs:14:24:14:31 | { ... } | P1 |
| PropertyPatterns.cs:14:29:14:29 | 1 | X |
| PropertyPatterns.cs:18:20:18:21 | { ... } | P1 |
| PropertyPatterns.cs:18:26:18:26 | 2 | X |
| PropertyPatterns.cs:25:23:25:38 | { ... } | L |
| PropertyPatterns.cs:25:29:25:36 | { ... } | P2 |
| PropertyPatterns.cs:25:34:25:34 | 3 | Y |
| PropertyPatterns.cs:29:20:29:20 | { ... } | L |
| PropertyPatterns.cs:29:22:29:23 | { ... } | P2 |
| PropertyPatterns.cs:29:28:29:28 | 4 | Y |
| PropertyPatterns.cs:36:23:36:33 | { ... } | L |
| PropertyPatterns.cs:36:25:36:26 | { ... } | P2 |
| PropertyPatterns.cs:36:31:36:31 | 5 | Y |
| PropertyPatterns.cs:40:20:40:20 | { ... } | L |
| PropertyPatterns.cs:40:26:40:33 | { ... } | P2 |
| PropertyPatterns.cs:40:31:40:31 | 6 | Y |
| PropertyPatterns.cs:47:24:47:31 | { ... } | P1 |
| PropertyPatterns.cs:47:29:47:29 | 7 | X |
| PropertyPatterns.cs:47:38:47:45 | { ... } | P1 |
| PropertyPatterns.cs:47:43:47:43 | 8 | Y |
| PropertyPatterns.cs:51:20:51:21 | { ... } | P1 |
| PropertyPatterns.cs:51:26:51:26 | 9 | X |
| PropertyPatterns.cs:51:29:51:30 | { ... } | P1 |
| PropertyPatterns.cs:51:35:51:36 | 10 | Y |

View File

@@ -0,0 +1,11 @@
import csharp
query predicate propertyPatterns(PropertyPatternExpr exp) { any() }
query predicate propertyPatternChild(PropertyPatternExpr pp, int n, PatternExpr child) {
child = pp.getPattern(n)
}
query predicate propertyPatternLabels(LabeledPatternExpr exp, string label) {
label = exp.getLabel()
}

View File

@@ -1,4 +1,7 @@
recordTypes
| PropertyPatterns.cs:3:1:3:34 | Point |
| PropertyPatterns.cs:4:1:4:39 | Line |
| PropertyPatterns.cs:5:1:5:27 | Wrap |
| RecordTypes.cs:3:1:6:2 | MyEntry |
| RecordTypes.cs:8:1:8:53 | MyClassRecord |
| RecordTypes.cs:10:1:10:70 | MyReadonlyRecordStruct |
@@ -9,5 +12,8 @@ recordStructs
| RecordTypes.cs:12:1:12:51 | MyRecordStruct1 |
| WithExpression.cs:9:1:9:47 | MyRecordStruct2 |
recordClass
| PropertyPatterns.cs:3:1:3:34 | Point |
| PropertyPatterns.cs:4:1:4:39 | Line |
| PropertyPatterns.cs:5:1:5:27 | Wrap |
| RecordTypes.cs:3:1:6:2 | MyEntry |
| RecordTypes.cs:8:1:8:53 | MyClassRecord |

View File

@@ -82,7 +82,7 @@ For example, the following query computes, for each folder, the number of JavaSc
Locations
^^^^^^^^^
Most entities in a CodeQL database have an associated source location. Locations are identified by four pieces of information: a file, a start line, a start column, an end line, and an end column. Line and column counts are 1-based (so the first character of a file is at line 1, column 1), and the end position is inclusive.
Most entities in a CodeQL database have an associated source location. Locations are identified by five pieces of information: a file, a start line, a start column, an end line, and an end column. Line and column counts are 1-based (so the first character of a file is at line 1, column 1), and the end position is inclusive.
All entities associated with a source location belong to the class `Locatable <https://codeql.github.com/codeql-standard-libraries/javascript/semmle/javascript/Locations.qll/type.Locations$Locatable.html>`__. The location itself is modeled by the class `Location <https://codeql.github.com/codeql-standard-libraries/javascript/semmle/javascript/Locations.qll/type.Locations$Location.html>`__ and can be accessed through the member predicate ``Locatable.getLocation()``. The `Location <https://codeql.github.com/codeql-standard-libraries/javascript/semmle/javascript/Locations.qll/type.Locations$Location.html>`__ class provides the following member predicates:

View File

@@ -33,7 +33,7 @@ java.lang,8,,58,,,,,,,,,,8,,,,,,,,,,,,,,,46,12
java.net,10,3,7,,,,,,,,,,,,,10,,,,,,,,,,,3,7,
java.nio,15,,6,,13,,,,,,,,,,,,,,,,,2,,,,,,6,
java.sql,7,,,,,,,,,,,,,,,,,,7,,,,,,,,,,
java.util,34,,430,,,,,,,,,,34,,,,,,,,,,,,,,,16,414
java.util,34,,438,,,,,,,,,,34,,,,,,,,,,,,,,,24,414
javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,2,,7,,
javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,100,23
javax.management.remote,2,,,,,,,,,,2,,,,,,,,,,,,,,,,,,
1 package sink source summary sink:bean-validation sink:create-file sink:groovy sink:header-splitting sink:information-leak sink:intent-start sink:jexl sink:jndi-injection sink:ldap sink:logging sink:mvel sink:ognl-injection sink:open-url sink:pending-intent-sent sink:set-hostname-verifier sink:sql sink:url-open-stream sink:url-redirect sink:write-file sink:xpath sink:xslt sink:xss source:contentprovider source:remote summary:taint summary:value
33 java.net 10 3 7 10 3 7
34 java.nio 15 6 13 2 6
35 java.sql 7 7
36 java.util 34 430 438 34 16 24 414
37 javax.faces.context 2 7 2 7
38 javax.json 123 100 23
39 javax.management.remote 2 2

View File

@@ -15,9 +15,9 @@ Java framework & library support
`Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,136,28,,,3,,,,25
`Google Guava <https://guava.dev/>`_,``com.google.common.*``,,728,35,,6,,,,,
`JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,,,
Java Standard Library,``java.*``,3,533,111,28,,,7,,,10
Java Standard Library,``java.*``,3,541,111,28,,,7,,,10
Java extensions,"``javax.*``, ``jakarta.*``",54,552,32,,,4,,1,1,2
`Spring <https://spring.io/>`_,``org.springframework.*``,29,472,96,,,,19,14,,29
Others,"``androidx.slice``, ``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.unboundid.ldap.sdk``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.logging.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jboss.logging``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``",44,283,921,,,,14,18,,
Totals,,182,6212,1424,106,6,10,107,33,1,81
Totals,,182,6220,1424,106,6,10,107,33,1,81

View File

@@ -1,4 +1,6 @@
name: codeql/java-examples
version: 0.0.2
groups:
- java
- examples
dependencies:
codeql/java-all: "*"
codeql/java-all: "*"

View File

@@ -78,10 +78,12 @@ private import FlowSummary
private module Frameworks {
private import internal.ContainerFlow
private import semmle.code.java.frameworks.android.Android
private import semmle.code.java.frameworks.android.ContentProviders
private import semmle.code.java.frameworks.android.Intent
private import semmle.code.java.frameworks.android.Notifications
private import semmle.code.java.frameworks.android.Slice
private import semmle.code.java.frameworks.android.SQLite
private import semmle.code.java.frameworks.android.Widget
private import semmle.code.java.frameworks.android.XssSinks
private import semmle.code.java.frameworks.ApacheHttp
private import semmle.code.java.frameworks.apache.Collections

View File

@@ -1290,7 +1290,7 @@ class DataFlowCallOption extends TDataFlowCallOption {
}
}
/** Content tagged with the type of a containing object. */
/** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;
private DataFlowType t;

View File

@@ -90,7 +90,9 @@ module Public {
predicate contains(SummaryComponent c) { c = this.drop(_).head() }
/** Gets the bottom element of this stack. */
SummaryComponent bottom() { result = this.drop(this.length() - 1).head() }
SummaryComponent bottom() {
this = TSingletonSummaryComponentStack(result) or result = this.tail().bottom()
}
/** Gets a textual representation of this stack. */
string toString() {

View File

@@ -25,6 +25,7 @@ class ThriftIface extends Interface {
this.getFile() instanceof ThriftGeneratedFile
}
/** Gets an implementation of a method of this interface. */
Method getAnImplementingMethod() {
result.getDeclaringType().(Class).getASupertype+() = this and
result.overrides+(this.getAMethod()) and

View File

@@ -177,42 +177,6 @@ private class UriModel extends SummaryModelCsv {
}
}
private class ContentProviderSourceModels extends SourceModelCsv {
override predicate row(string row) {
row =
[
// ContentInterface models are here for backwards compatibility (it was removed in API 28)
"android.content;ContentInterface;true;call;(String,String,String,Bundle);;Parameter[0..3];contentprovider",
"android.content;ContentProvider;true;call;(String,String,String,Bundle);;Parameter[0..3];contentprovider",
"android.content;ContentProvider;true;call;(String,String,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;delete;(Uri,String,String[]);;Parameter[0..2];contentprovider",
"android.content;ContentInterface;true;delete;(Uri,Bundle);;Parameter[0..1];contentprovider",
"android.content;ContentProvider;true;delete;(Uri,Bundle);;Parameter[0..1];contentprovider",
"android.content;ContentInterface;true;getType;(Uri);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;getType;(Uri);;Parameter[0];contentprovider",
"android.content;ContentInterface;true;insert;(Uri,ContentValues,Bundle);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;insert;(Uri,ContentValues,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;insert;(Uri,ContentValues);;Parameter[0..1];contentprovider",
"android.content;ContentInterface;true;openAssetFile;(Uri,String,CancellationSignal);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;openAssetFile;(Uri,String,CancellationSignal);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;openAssetFile;(Uri,String);;Parameter[0];contentprovider",
"android.content;ContentInterface;true;openTypedAssetFile;(Uri,String,Bundle,CancellationSignal);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;openTypedAssetFile;(Uri,String,Bundle,CancellationSignal);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;openTypedAssetFile;(Uri,String,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentInterface;true;openFile;(Uri,String,CancellationSignal);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;openFile;(Uri,String,CancellationSignal);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;openFile;(Uri,String);;Parameter[0];contentprovider",
"android.content;ContentInterface;true;query;(Uri,String[],Bundle,CancellationSignal);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;query;(Uri,String[],Bundle,CancellationSignal);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;query;(Uri,String[],String,String[],String);;Parameter[0..4];contentprovider",
"android.content;ContentProvider;true;query;(Uri,String[],String,String[],String,CancellationSignal);;Parameter[0..4];contentprovider",
"android.content;ContentInterface;true;update;(Uri,ContentValues,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;update;(Uri,ContentValues,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;update;(Uri,ContentValues,String,String[]);;Parameter[0..3];contentprovider"
]
}
}
/** Interface for classes whose instances can be written to and restored from a Parcel. */
class TypeParcelable extends Interface {
TypeParcelable() { this.hasQualifiedName("android.os", "Parcelable") }

View File

@@ -0,0 +1,59 @@
/**
* Provides classes and predicates for working with Content Providers.
*/
import java
import semmle.code.java.dataflow.ExternalFlow
/** The class `android.content.ContentValues`. */
class ContentValues extends Class {
ContentValues() { this.hasQualifiedName("android.content", "ContentValues") }
}
private class ContentProviderSourceModels extends SourceModelCsv {
override predicate row(string row) {
row =
[
// ContentInterface models are here for backwards compatibility (it was removed in API 28)
"android.content;ContentInterface;true;call;(String,String,String,Bundle);;Parameter[0..3];contentprovider",
"android.content;ContentProvider;true;call;(String,String,String,Bundle);;Parameter[0..3];contentprovider",
"android.content;ContentProvider;true;call;(String,String,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;delete;(Uri,String,String[]);;Parameter[0..2];contentprovider",
"android.content;ContentInterface;true;delete;(Uri,Bundle);;Parameter[0..1];contentprovider",
"android.content;ContentProvider;true;delete;(Uri,Bundle);;Parameter[0..1];contentprovider",
"android.content;ContentInterface;true;getType;(Uri);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;getType;(Uri);;Parameter[0];contentprovider",
"android.content;ContentInterface;true;insert;(Uri,ContentValues,Bundle);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;insert;(Uri,ContentValues,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;insert;(Uri,ContentValues);;Parameter[0..1];contentprovider",
"android.content;ContentInterface;true;openAssetFile;(Uri,String,CancellationSignal);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;openAssetFile;(Uri,String,CancellationSignal);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;openAssetFile;(Uri,String);;Parameter[0];contentprovider",
"android.content;ContentInterface;true;openTypedAssetFile;(Uri,String,Bundle,CancellationSignal);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;openTypedAssetFile;(Uri,String,Bundle,CancellationSignal);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;openTypedAssetFile;(Uri,String,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentInterface;true;openFile;(Uri,String,CancellationSignal);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;openFile;(Uri,String,CancellationSignal);;Parameter[0];contentprovider",
"android.content;ContentProvider;true;openFile;(Uri,String);;Parameter[0];contentprovider",
"android.content;ContentInterface;true;query;(Uri,String[],Bundle,CancellationSignal);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;query;(Uri,String[],Bundle,CancellationSignal);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;query;(Uri,String[],String,String[],String);;Parameter[0..4];contentprovider",
"android.content;ContentProvider;true;query;(Uri,String[],String,String[],String,CancellationSignal);;Parameter[0..4];contentprovider",
"android.content;ContentInterface;true;update;(Uri,ContentValues,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;update;(Uri,ContentValues,Bundle);;Parameter[0..2];contentprovider",
"android.content;ContentProvider;true;update;(Uri,ContentValues,String,String[]);;Parameter[0..3];contentprovider"
]
}
}
private class SummaryModels extends SummaryModelCsv {
override predicate row(string row) {
row =
[
"android.content;ContentValues;false;put;;;Argument[0];MapKey of Argument[-1];value",
"android.content;ContentValues;false;put;;;Argument[1];MapValue of Argument[-1];value",
"android.content;ContentValues;false;putAll;;;MapKey of Argument[0];MapKey of Argument[-1];value",
"android.content;ContentValues;false;putAll;;;MapValue of Argument[0];MapValue of Argument[-1];value"
]
}
}

View File

@@ -1,3 +1,5 @@
/** Provides classes and predicates for working with SQLite databases. */
import java
import Android
import semmle.code.java.dataflow.FlowSteps
@@ -24,6 +26,20 @@ class TypeDatabaseUtils extends Class {
TypeDatabaseUtils() { hasQualifiedName("android.database", "DatabaseUtils") }
}
/**
* The class `android.database.sqlite.SQLiteOpenHelper`.
*/
class TypeSQLiteOpenHelper extends Class {
TypeSQLiteOpenHelper() { this.hasQualifiedName("android.database.sqlite", "SQLiteOpenHelper") }
}
/**
* The class `android.database.sqlite.SQLiteStatement`.
*/
class TypeSQLiteStatement extends Class {
TypeSQLiteStatement() { this.hasQualifiedName("android.database.sqlite", "SQLiteStatement") }
}
private class SQLiteSinkCsv extends SinkModelCsv {
override predicate row(string row) {
row =

View File

@@ -0,0 +1,23 @@
/** Provides classes and predicates for working with Android widgets. */
import java
import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.dataflow.FlowSources
private class AndroidWidgetSourceModels extends SourceModelCsv {
override predicate row(string row) {
row = "android.widget;EditText;true;getText;;;ReturnValue;android-widget"
}
}
private class DefaultAndroidWidgetSources extends RemoteFlowSource {
DefaultAndroidWidgetSources() { sourceNode(this, "android-widget") }
override string getSourceType() { result = "Android widget source" }
}
private class AndroidWidgetSummaryModels extends SummaryModelCsv {
override predicate row(string row) {
row = "android.widget;EditText;true;getText;;;Argument[-1];ReturnValue;taint"
}
}

View File

@@ -15,6 +15,7 @@ class StrutsAnnotation extends Annotation {
class StrutsActionAnnotation extends StrutsAnnotation {
StrutsActionAnnotation() { this.getType().hasName("Action") }
/** Gets a callable annotated with this annotation. */
Callable getActionCallable() {
result = this.getAnnotatedElement()
or

View File

@@ -0,0 +1,131 @@
/** Provides classes and predicates to reason about cleartext storage in Android databases. */
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.frameworks.android.ContentProviders
import semmle.code.java.frameworks.android.Intent
import semmle.code.java.frameworks.android.SQLite
import semmle.code.java.security.CleartextStorageQuery
private class LocalDatabaseCleartextStorageSink extends CleartextStorageSink {
LocalDatabaseCleartextStorageSink() { localDatabaseInput(_, this.asExpr()) }
}
private class LocalDatabaseCleartextStorageStep extends CleartextStorageAdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
// EditText.getText() return type is parsed as `Object`, so we need to
// add a taint step for `Object.toString` to model `editText.getText().toString()`
exists(MethodAccess ma, Method m |
ma.getMethod() = m and
m.getDeclaringType() instanceof TypeObject and
m.hasName("toString")
|
n1.asExpr() = ma.getQualifier() and n2.asExpr() = ma
)
}
}
/** The creation of an object that can be used to store data in a local database. */
class LocalDatabaseOpenMethodAccess extends Storable, Call {
LocalDatabaseOpenMethodAccess() {
exists(Method m | this.(MethodAccess).getMethod() = m |
m.getDeclaringType().getASupertype*() instanceof TypeSQLiteOpenHelper and
m.hasName("getWritableDatabase")
or
m.getDeclaringType() instanceof TypeSQLiteDatabase and
m.hasName(["create", "openDatabase", "openOrCreateDatabase", "compileStatement"])
or
m.getDeclaringType().getASupertype*() instanceof TypeContext and
m.hasName("openOrCreateDatabase")
)
or
this.(ClassInstanceExpr).getConstructedType() instanceof ContentValues
}
override Expr getAnInput() {
exists(LocalDatabaseFlowConfig config, DataFlow::Node database |
localDatabaseInput(database, result) and
config.hasFlow(DataFlow::exprNode(this), database)
)
}
override Expr getAStore() {
exists(LocalDatabaseFlowConfig config, DataFlow::Node database |
localDatabaseStore(database, result) and
config.hasFlow(DataFlow::exprNode(this), database)
)
}
}
/** A method that is both a database input and a database store. */
private class LocalDatabaseInputStoreMethod extends Method {
LocalDatabaseInputStoreMethod() {
this.getDeclaringType() instanceof TypeSQLiteDatabase and
this.getName().matches("exec%SQL")
}
}
/**
* Holds if `input` is a value being prepared for being stored into the SQLite dataabse `database`.
* This can be done using prepared statements, using the class `ContentValues`, or directly
* appending `input` to a SQL query.
*/
private predicate localDatabaseInput(DataFlow::Node database, Argument input) {
exists(Method m | input.getCall().getCallee() = m |
m instanceof LocalDatabaseInputStoreMethod and
database.asExpr() = input.getCall().getQualifier()
or
m.getDeclaringType() instanceof TypeSQLiteDatabase and
m.hasName("compileStatement") and
database.asExpr() = input.getCall()
or
m.getDeclaringType() instanceof ContentValues and
m.hasName("put") and
input.getPosition() = 1 and
database.asExpr() = input.getCall().getQualifier()
)
}
/**
* Holds if `store` is a method call for storing a previously appended input value,
* either through the use of prepared statements, via the `ContentValues` class, or
* directly executing a raw SQL query.
*/
private predicate localDatabaseStore(DataFlow::Node database, MethodAccess store) {
exists(Method m | store.getMethod() = m |
m instanceof LocalDatabaseInputStoreMethod and
database.asExpr() = store.getQualifier()
or
m.getDeclaringType() instanceof TypeSQLiteDatabase and
m.getName().matches(["insert%", "replace%", "update%"]) and
database.asExpr() = store.getAnArgument() and
database.getType() instanceof ContentValues
or
m.getDeclaringType() instanceof TypeSQLiteStatement and
m.hasName(["executeInsert", "executeUpdateDelete"]) and
database.asExpr() = store.getQualifier()
)
}
private class LocalDatabaseFlowConfig extends DataFlow::Configuration {
LocalDatabaseFlowConfig() { this = "LocalDatabaseFlowConfig" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof LocalDatabaseOpenMethodAccess
}
override predicate isSink(DataFlow::Node sink) {
localDatabaseInput(sink, _) or
localDatabaseStore(sink, _)
}
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
// Adds a step for tracking databases through field flow, that is, a database is opened and
// assigned to a field, and then an input or store method is called on that field elsewhere.
exists(Field f |
f.getType() instanceof TypeSQLiteDatabase and
f.getAnAssignedValue() = n1.asExpr() and
f = n2.asExpr().(FieldRead).getField()
)
}
}

View File

@@ -14,7 +14,11 @@
import java
private string suspicious() {
result = ["%password%", "%passwd%", "%account%", "%accnt%", "%trusted%"]
result =
[
"%password%", "%passwd%", "pwd", "%account%", "%accnt%", "%trusted%", "%refresh%token%",
"%secret%token"
]
}
private string nonSuspicious() {

View File

@@ -6,122 +6,22 @@
*/
class Person extends string {
Person() {
this = "Ronil" or
this = "Dina" or
this = "Ravi" or
this = "Bruce" or
this = "Jo" or
this = "Aida" or
this = "Esme" or
this = "Charlie" or
this = "Fred" or
this = "Meera" or
this = "Maya" or
this = "Chad" or
this = "Tiana" or
this = "Laura" or
this = "George" or
this = "Will" or
this = "Mary" or
this = "Almira" or
this = "Susannah" or
this = "Rhoda" or
this = "Cynthia" or
this = "Eunice" or
this = "Olive" or
this = "Virginia" or
this = "Angeline" or
this = "Helen" or
this = "Cornelia" or
this = "Harriet" or
this = "Mahala" or
this = "Abby" or
this = "Margaret" or
this = "Deb" or
this = "Minerva" or
this = "Severus" or
this = "Lavina" or
this = "Adeline" or
this = "Cath" or
this = "Elisa" or
this = "Lucretia" or
this = "Anne" or
this = "Eleanor" or
this = "Joanna" or
this = "Adam" or
this = "Agnes" or
this = "Rosanna" or
this = "Clara" or
this = "Melissa" or
this = "Amy" or
this = "Isabel" or
this = "Jemima" or
this = "Cordelia" or
this = "Melinda" or
this = "Delila" or
this = "Jeremiah" or
this = "Elijah" or
this = "Hester" or
this = "Walter" or
this = "Oliver" or
this = "Hugh" or
this = "Aaron" or
this = "Reuben" or
this = "Eli" or
this = "Amos" or
this = "Augustus" or
this = "Theodore" or
this = "Ira" or
this = "Timothy" or
this = "Cyrus" or
this = "Horace" or
this = "Simon" or
this = "Asa" or
this = "Frank" or
this = "Nelson" or
this = "Leonard" or
this = "Harrison" or
this = "Anthony" or
this = "Louis" or
this = "Milton" or
this = "Noah" or
this = "Cornelius" or
this = "Abdul" or
this = "Warren" or
this = "Harvey" or
this = "Dennis" or
this = "Wesley" or
this = "Sylvester" or
this = "Gilbert" or
this = "Sullivan" or
this = "Edmund" or
this = "Wilson" or
this = "Perry" or
this = "Matthew" or
this = "Simba" or
this = "Nala" or
this = "Rafiki" or
this = "Shenzi" or
this = "Ernest" or
this = "Gertrude" or
this = "Oscar" or
this = "Lilian" or
this = "Raymond" or
this = "Elgar" or
this = "Elmer" or
this = "Herbert" or
this = "Maude" or
this = "Mae" or
this = "Otto" or
this = "Edwin" or
this = "Ophelia" or
this = "Parsley" or
this = "Sage" or
this = "Rosemary" or
this = "Thyme" or
this = "Garfunkel" or
this = "King Basil" or
this = "Stephen"
this =
[
"Ronil", "Dina", "Ravi", "Bruce", "Jo", "Aida", "Esme", "Charlie", "Fred", "Meera", "Maya",
"Chad", "Tiana", "Laura", "George", "Will", "Mary", "Almira", "Susannah", "Rhoda",
"Cynthia", "Eunice", "Olive", "Virginia", "Angeline", "Helen", "Cornelia", "Harriet",
"Mahala", "Abby", "Margaret", "Deb", "Minerva", "Severus", "Lavina", "Adeline", "Cath",
"Elisa", "Lucretia", "Anne", "Eleanor", "Joanna", "Adam", "Agnes", "Rosanna", "Clara",
"Melissa", "Amy", "Isabel", "Jemima", "Cordelia", "Melinda", "Delila", "Jeremiah", "Elijah",
"Hester", "Walter", "Oliver", "Hugh", "Aaron", "Reuben", "Eli", "Amos", "Augustus",
"Theodore", "Ira", "Timothy", "Cyrus", "Horace", "Simon", "Asa", "Frank", "Nelson",
"Leonard", "Harrison", "Anthony", "Louis", "Milton", "Noah", "Cornelius", "Abdul", "Warren",
"Harvey", "Dennis", "Wesley", "Sylvester", "Gilbert", "Sullivan", "Edmund", "Wilson",
"Perry", "Matthew", "Simba", "Nala", "Rafiki", "Shenzi", "Ernest", "Gertrude", "Oscar",
"Lilian", "Raymond", "Elgar", "Elmer", "Herbert", "Maude", "Mae", "Otto", "Edwin",
"Ophelia", "Parsley", "Sage", "Rosemary", "Thyme", "Garfunkel", "King Basil", "Stephen"
]
}
/** Gets the hair color of the person. If the person is bald, there is no result. */
@@ -936,25 +836,12 @@ class Person extends string {
/** Holds if the person is deceased. */
predicate isDeceased() {
this = "Ernest" or
this = "Gertrude" or
this = "Oscar" or
this = "Lilian" or
this = "Edwin" or
this = "Raymond" or
this = "Elgar" or
this = "Elmer" or
this = "Herbert" or
this = "Maude" or
this = "Mae" or
this = "Otto" or
this = "Ophelia" or
this = "Parsley" or
this = "Sage" or
this = "Rosemary" or
this = "Thyme" or
this = "Garfunkel" or
this = "King Basil"
this =
[
"Ernest", "Gertrude", "Oscar", "Lilian", "Edwin", "Raymond", "Elgar", "Elmer", "Herbert",
"Maude", "Mae", "Otto", "Ophelia", "Parsley", "Sage", "Rosemary", "Thyme", "Garfunkel",
"King Basil"
]
}
/** Gets a parent of the person (alive or deceased). */
@@ -1195,12 +1082,7 @@ class Person extends string {
}
/** Holds if the person is allowed in the region. Initially, all villagers are allowed in every region. */
predicate isAllowedIn(string region) {
region = "north" or
region = "south" or
region = "east" or
region = "west"
}
predicate isAllowedIn(string region) { region = ["north", "south", "east", "west"] }
}
/** Returns a parent of the person. */

View File

@@ -0,0 +1,27 @@
public void sqliteStorageUnsafe(Context ctx, String name, String password) {
// BAD - sensitive information saved in cleartext.
SQLiteDatabase db = ctx.openOrCreateDatabase("test", Context.MODE_PRIVATE, null);
db.execSQL("INSERT INTO users VALUES (?, ?)", new String[] {name, password});
}
public void sqliteStorageSafe(Context ctx, String name, String password) {
// GOOD - sensitive information encrypted with a custom method.
SQLiteDatabase db = ctx.openOrCreateDatabase("test", Context.MODE_PRIVATE, null);
db.execSQL("INSERT INTO users VALUES (?, ?)", new String[] {name, encrypt(password)});
}
public void sqlCipherStorageSafe(String name, String password, String databasePassword) {
// GOOD - sensitive information saved using SQLCipher.
net.sqlcipher.database.SQLiteDatabase db =
net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase("test", databasePassword, null);
db.execSQL("INSERT INTO users VALUES (?, ?)", new String[] {name, password});
}
private static String encrypt(String cleartext) {
// Use an encryption or strong hashing algorithm in the real world.
// The example below just returns a SHA-256 hash.
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(cleartext.getBytes(StandardCharsets.UTF_8));
String encoded = Base64.getEncoder().encodeToString(hash);
return encoded;
}

View File

@@ -0,0 +1,36 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
SQLite is a lightweight database engine commonly used in Android devices to store data. By itself, SQLite does not offer any encryption mechanism by default and stores all data in cleartext, which introduces a risk if sensitive data like credentials, authentication tokens or personal identifiable information (PII) are directly stored in a SQLite database. The information could be accessed by any process or user in rooted devices, or can be disclosed through chained vulnerabilities, like unexpected access to the private storage through exposed components.
</p>
</overview>
<recommendation>
<p>
Use <code>SQLCipher</code> or similar libraries to add encryption capabilities to SQLite. Alternatively, encrypt sensitive data using cryptographically secure algorithms before storing it in the database.
</p>
</recommendation>
<example>
<p>
In the first example, sensitive user information is stored in cleartext.
</p>
<p>
In the second and third examples, the code encrypts sensitive information before saving it to the database.
</p>
<sample src="CleartextStorageAndroidDatabase.java" />
</example>
<references>
<li>
Android Developers:
<a href="https://developer.android.com/topic/security/data">Work with data more securely</a>
</li>
<li>
SQLCipher:
<a href="https://www.zetetic.net/sqlcipher/sqlcipher-for-android/">Android Application Integration</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,23 @@
/**
* @name Cleartext storage of sensitive information using a local database on Android
* @description Cleartext Storage of Sensitive Information using
* a local database on Android allows access for users with root
* privileges or unexpected exposure from chained vulnerabilities.
* @kind problem
* @problem.severity warning
* @precision medium
* @id java/android/cleartext-storage-database
* @tags security
* external/cwe/cwe-312
*/
import java
import semmle.code.java.security.CleartextStorageAndroidDatabaseQuery
from SensitiveSource data, LocalDatabaseOpenMethodAccess s, Expr input, Expr store
where
input = s.getAnInput() and
store = s.getAStore() and
data.flowsTo(input)
select store, "SQLite database $@ containing $@ is stored $@. Data was added $@.", s, s.toString(),
data, "sensitive data", store, "here", input, "here"

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* A new query "Cleartext storage of sensitive information using a local database on Android" (`java/android/cleartext-storage-database`) has been added. This query finds instances of sensitive data being stored in local databases without encryption, which may expose it to attackers or malicious applications.

View File

@@ -1,9 +1,11 @@
name: codeql/java-queries
version: 0.0.8-dev
groups: java
groups:
- java
- queries
suites: codeql-suites
extractor: java
defaultSuiteFile: codeql-suites/java-code-scanning.qls
dependencies:
codeql/java-all: "*"
codeql/suite-helpers: "*"
codeql/java-all: "*"
codeql/suite-helpers: "*"

View File

@@ -93,7 +93,7 @@
private import InlineExpectationsTestPrivate
/**
* Base class for tests with inline expectations. The test extends this class to provide the actual
* The base class for tests with inline expectations. The test extends this class to provide the actual
* results of the query, which are then compared with the expected results in comments to produce a
* list of failure messages that point out where the actual results differ from the expected
* results.

View File

@@ -0,0 +1,144 @@
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
public class CleartextStorageAndroidDatabaseTest extends Activity {
public void testCleartextStorageAndroiDatabaseSafe1(Context ctx, String name, String password) {
SQLiteDatabase db = ctx.openOrCreateDatabase("test", Context.MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS users(user VARCHAR, password VARCHAR);"); // Safe
}
public void testCleartextStorageAndroiDatabaseSafe2(Context ctx, String name, String password) {
SQLiteDatabase db = ctx.openOrCreateDatabase("test", Context.MODE_PRIVATE, null);
db.execSQL("DROP TABLE passwords;"); // Safe - no sensitive value being stored
}
public void testCleartextStorageAndroiDatabase0(Context ctx, String name, String password) {
SQLiteDatabase db = ctx.openOrCreateDatabase("test", Context.MODE_PRIVATE, null);
String query = "INSERT INTO users VALUES ('" + name + "', '" + password + "');";
db.execSQL(query); // $ hasCleartextStorageAndroidDatabase
}
public void testCleartextStorageAndroiDatabase1(Context ctx, String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openDatabase("", null, 0);
String query = "INSERT INTO users VALUES ('" + name + "', '" + password + "');";
db.execSQL(query); // $ hasCleartextStorageAndroidDatabase
}
public void testCleartextStorageAndroiDatabase2(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("", null);
String query = "INSERT INTO users VALUES (?, ?)";
db.execSQL(query, new String[] {name, password}); // $ hasCleartextStorageAndroidDatabase
}
//@formatter:off
public void testCleartextStorageAndroiDatabase3(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.create(null);
String query = "INSERT INTO users VALUES (?, ?)";
db.execPerConnectionSQL(query, new String[] {name, password}); // $ hasCleartextStorageAndroidDatabase
}
//@formatter:on
public void testCleartextStorageAndroiDatabaseSafe3(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openDatabase("", null, 0);
ContentValues cv = new ContentValues();
cv.put("username", name);
cv.put("password", password); // Safe - ContentValues aren't added to any database
}
public void testCleartextStorageAndroiDatabase4(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openDatabase("", null, 0);
ContentValues cv = new ContentValues();
cv.put("username", name);
cv.put("password", password); // $ hasCleartextStorageAndroidDatabase
db.insert("table", null, cv);
}
public void testCleartextStorageAndroiDatabase5(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openDatabase("", null, 0);
ContentValues cv = new ContentValues();
cv.put("username", name);
cv.put("password", password); // $ hasCleartextStorageAndroidDatabase
db.insertOrThrow("table", null, cv);
}
public void testCleartextStorageAndroiDatabase6(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openDatabase("", null, 0);
ContentValues cv = new ContentValues();
cv.put("username", name);
cv.put("password", password); // $ hasCleartextStorageAndroidDatabase
db.insertWithOnConflict("table", null, cv, 0);
}
public void testCleartextStorageAndroiDatabase7(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openDatabase("", null, 0);
ContentValues cv = new ContentValues();
cv.put("username", name);
cv.put("password", password); // $ hasCleartextStorageAndroidDatabase
db.replace("table", null, cv);
}
public void testCleartextStorageAndroiDatabase8(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openDatabase("", null, 0);
ContentValues cv = new ContentValues();
cv.put("username", name);
cv.put("password", password); // $ hasCleartextStorageAndroidDatabase
db.replaceOrThrow("table", null, cv);
}
public void testCleartextStorageAndroiDatabase9(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openDatabase("", null, 0);
ContentValues cv = new ContentValues();
cv.put("username", name);
cv.put("password", password); // $ hasCleartextStorageAndroidDatabase
db.update("table", cv, "", new String[] {});
}
public void testCleartextStorageAndroiDatabase10(String name, String password) {
SQLiteDatabase db = SQLiteDatabase.openDatabase("", null, 0);
ContentValues cv = new ContentValues();
cv.put("username", name);
cv.put("password", password); // $ hasCleartextStorageAndroidDatabase
db.updateWithOnConflict("table", cv, "", new String[] {}, 0);
}
public void testCleartextStorageAndroiDatabaseSafe4(SQLiteDatabase db, String name,
String password) {
String query = "INSERT INTO users VALUES ('" + name + "', '" + password + "');";
SQLiteStatement stmt = db.compileStatement(query); // Safe - statement isn't executed
}
public void testCleartextStorageAndroiDatabase11(SQLiteDatabase db, String name,
String password) {
String query = "INSERT INTO users VALUES ('" + name + "', '" + password + "');";
SQLiteStatement stmt = db.compileStatement(query); // $ hasCleartextStorageAndroidDatabase
stmt.executeUpdateDelete();
}
public void testCleartextStorageAndroiDatabase12(SQLiteDatabase db, String name,
String password) {
String query = "INSERT INTO users VALUES ('" + name + "', '" + password + "');";
SQLiteStatement stmt = db.compileStatement(query); // $ hasCleartextStorageAndroidDatabase
stmt.executeInsert();
}
public void testCleartextStorageAndroiDatabaseSafe5(String name, String password)
throws Exception {
SQLiteDatabase db = SQLiteDatabase.create(null);
String query = "INSERT INTO users VALUES (?, ?)";
db.execSQL(query, new String[] {name, encrypt(password)}); // Safe
}
private static String encrypt(String cleartext) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(cleartext.getBytes(StandardCharsets.UTF_8));
String encoded = Base64.getEncoder().encodeToString(hash);
return encoded;
}
}

View File

@@ -0,0 +1,22 @@
import java
import semmle.code.java.security.CleartextStorageAndroidDatabaseQuery
import TestUtilities.InlineExpectationsTest
class CleartextStorageAndroidDatabaseTest extends InlineExpectationsTest {
CleartextStorageAndroidDatabaseTest() { this = "CleartextStorageAndroidDatabaseTest" }
override string getARelevantTag() { result = "hasCleartextStorageAndroidDatabase" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "hasCleartextStorageAndroidDatabase" and
exists(SensitiveSource data, LocalDatabaseOpenMethodAccess s, Expr input, Expr store |
input = s.getAnInput() and
store = s.getAStore() and
data.flowsTo(input)
|
input.getLocation() = location and
element = input.toString() and
value = ""
)
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package android.annotation;
public @interface IntRange {
long from() default Long.MIN_VALUE;
long to() default Long.MAX_VALUE;
}

View File

@@ -0,0 +1,46 @@
package android.database;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.ParcelFileDescriptor;
public class DatabaseUtils {
public static ParcelFileDescriptor blobFileDescriptorForQuery(SQLiteDatabase db, String query,
String[] selectionArgs) {
return null;
}
public static long longForQuery(SQLiteDatabase db, String query, String[] selectionArgs) {
return 0;
}
public static String stringForQuery(SQLiteDatabase db, String query, String[] selectionArgs) {
return null;
}
public static void createDbFromSqlStatements(Context context, String dbName, int dbVersion, String sqlStatements) {
}
public static int queryNumEntries(SQLiteDatabase db, String table, String selection) {
return 0;
}
public static int queryNumEntries(SQLiteDatabase db, String table, String selection, String[] selectionArgs) {
return 0;
}
public static String[] appendSelectionArgs(String[] originalValues, String[] newValues) {
return null;
}
public static String concatenateWhere(String a, String b) {
return null;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.database;
public class SQLException extends RuntimeException {
public SQLException() {
}
public SQLException(String error) {
}
public SQLException(String error, Throwable cause) {
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.database.sqlite;
import android.database.SQLException;
public class SQLiteException extends SQLException {
public SQLiteException() {
}
public SQLiteException(String error) {
}
public SQLiteException(String error, Throwable cause) {
}
}

View File

@@ -0,0 +1,57 @@
package android.database.sqlite;
import java.util.Map;
import java.util.Set;
import android.content.ContentValues;
import android.os.CancellationSignal;
public abstract class SQLiteQueryBuilder {
public abstract void delete(SQLiteDatabase db, String selection, String[] selectionArgs);
public abstract void insert(SQLiteDatabase db, ContentValues values);
public abstract void query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs,
String groupBy, String having, String sortOrder);
public abstract void query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs,
String groupBy, String having, String sortOrder, String limit);
public abstract void query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs,
String groupBy, String having, String sortOrder, String limit, CancellationSignal cancellationSignal);
public abstract void update(SQLiteDatabase db, ContentValues values, String selection, String[] selectionArgs);
public static String buildQueryString(boolean distinct, String tables, String[] columns, String where,
String groupBy, String having, String orderBy, String limit) {
return null;
}
public abstract String buildQuery(String[] projectionIn, String selection, String groupBy, String having, String sortOrder,
String limit);
public abstract String buildQuery(String[] projectionIn, String selection, String[] selectionArgs, String groupBy,
String having, String sortOrder, String limit);
public abstract String buildUnionQuery(String[] subQueries, String sortOrder, String limit);
public abstract String buildUnionSubQuery(String typeDiscriminatorColumn, String[] unionColumns,
Set<String> columnsPresentInTable, int computedColumnsOffset, String typeDiscriminatorValue,
String selection, String[] selectionArgs, String groupBy, String having);
public abstract String buildUnionSubQuery(String typeDiscriminatorColumn, String[] unionColumns,
Set<String> columnsPresentInTable, int computedColumnsOffset, String typeDiscriminatorValue,
String selection, String groupBy, String having);
public static void appendColumns(StringBuilder s, String[] columns) {
}
public abstract void setProjectionMap(Map<String, String> columnMap);
public abstract void setTables(String inTables);
public abstract void appendWhere(CharSequence inWhere);
public abstract void appendWhereStandalone(CharSequence inWhere);
}

View File

@@ -16,7 +16,6 @@
package android.webkit;
import java.io.InputStream;
import java.io.StringBufferInputStream;
import java.util.Map;
/**

View File

@@ -15,11 +15,8 @@
*/
package android.webkit;
import java.net.CookieManager;
import android.content.Context;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Manages settings state for a WebView. When a WebView is first created, it

View File

@@ -18,6 +18,7 @@ import android.content.Context;
import android.view.View;
public class WebView extends View {
public WebView(Context context) {
super(context);
}

View File

@@ -15,9 +15,6 @@
*/
package android.webkit;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class WebViewClient {
/**
* Give the host application a chance to take over the control when a new url is

View File

@@ -1,4 +1,6 @@
name: codeql/javascript-examples
version: 0.0.3
groups:
- javascript
- examples
dependencies:
codeql/javascript-all: "*"

View File

@@ -0,0 +1,67 @@
/**
* @name Debug result inclusion
* @description Use this query to understand why some alerts are included or excluded from the
* results of boosted queries. The results for this query are the union of the alerts
* generated by each boosted query. Each alert includes an explanation why it was
* included or excluded for each of the four security queries.
* @kind problem
* @problem.severity error
* @id adaptive-threat-modeling/js/debug-result-inclusion
*/
import javascript
import experimental.adaptivethreatmodeling.ATMConfig
import extraction.ExtractEndpointData
string getAReasonSinkExcluded(DataFlow::Node sinkCandidate, Query query) {
query instanceof NosqlInjectionQuery and
result = NosqlInjectionATM::SinkEndpointFilter::getAReasonSinkExcluded(sinkCandidate)
or
query instanceof SqlInjectionQuery and
result = SqlInjectionATM::SinkEndpointFilter::getAReasonSinkExcluded(sinkCandidate)
or
query instanceof TaintedPathQuery and
result = TaintedPathATM::SinkEndpointFilter::getAReasonSinkExcluded(sinkCandidate)
or
query instanceof XssQuery and
result = XssATM::SinkEndpointFilter::getAReasonSinkExcluded(sinkCandidate)
}
pragma[inline]
string getDescriptionForAlertCandidate(
DataFlow::Node sourceCandidate, DataFlow::Node sinkCandidate, Query query
) {
result = "excluded[reason=" + getAReasonSinkExcluded(sinkCandidate, query) + "]"
or
getATMCfg(query).isKnownSink(sinkCandidate) and
result = "excluded[reason=known-sink]"
or
not exists(getAReasonSinkExcluded(sinkCandidate, query)) and
not getDataFlowCfg(query).hasFlow(sourceCandidate, sinkCandidate) and
(
if
getDataFlowCfg(query).isSource(sourceCandidate) or
getDataFlowCfg(query).isSource(sourceCandidate, _)
then result = "no flow"
else result = "not a known source"
)
or
getDataFlowCfg(query).hasFlow(sourceCandidate, sinkCandidate) and
result = "included"
}
pragma[inline]
string getDescriptionForAlert(DataFlow::Node sourceCandidate, DataFlow::Node sinkCandidate) {
result =
concat(Query query |
|
query.getName() + ": " +
getDescriptionForAlertCandidate(sourceCandidate, sinkCandidate, query), ", "
)
}
from DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink
where cfg.hasFlow(source, sink)
select sink,
"This is an ATM result that may depend on $@ [" + getDescriptionForAlert(source, sink) + "]",
source, "a user-provided value"

View File

@@ -0,0 +1,11 @@
private import javascript
private import extraction.Exclusions as Exclusions
/**
* Holds if the flow from `source` to `sink` should be excluded from the results of an end-to-end
* evaluation query.
*/
pragma[inline]
predicate isFlowExcluded(DataFlow::Node source, DataFlow::Node sink) {
Exclusions::isFileExcluded([source.getFile(), sink.getFile()])
}

View File

@@ -0,0 +1,27 @@
/**
* EndpointScoresIntegrationTest.ql
*
* Extract scores for each test endpoint that is an argument to a function call in the database.
* This is used by integration tests to verify that QL and the modeling codebase agree on the scores
* of a set of test endpoints.
*/
import javascript
import experimental.adaptivethreatmodeling.ATMConfig
import experimental.adaptivethreatmodeling.FeaturizationConfig
import experimental.adaptivethreatmodeling.EndpointScoring::ModelScoring as ModelScoring
/**
* A featurization config that featurizes endpoints that are arguments to function calls.
*
* This should only be used in extraction queries and tests.
*/
class FunctionArgumentFeaturizationConfig extends FeaturizationConfig {
FunctionArgumentFeaturizationConfig() { this = "FunctionArgumentFeaturization" }
override DataFlow::Node getAnEndpointToFeaturize() {
exists(DataFlow::CallNode call | result = call.getAnArgument())
}
}
query predicate endpointScores = ModelScoring::endpointScores/3;

View File

@@ -0,0 +1,16 @@
/**
* ModelCheck.ql
*
* Returns checksums of ATM models.
*/
/**
* The `availableMlModels` template predicate.
*
* This is populated by the evaluator with metadata for the available machine learning models.
*/
external predicate availableMlModels(
string modelChecksum, string modelLanguage, string modelName, string modelType
);
select any(string checksum | availableMlModels(checksum, "javascript", _, _))

View File

@@ -0,0 +1,24 @@
/**
* NosqlInjection.ql
*
* Version of the standard NoSQL injection query with an output relation ready to plug into the
* evaluation pipeline.
*/
import semmle.javascript.security.dataflow.NosqlInjection
import EndToEndEvaluation as EndToEndEvaluation
from
DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink, string filePathSink,
int startLineSink, int endLineSink, int startColumnSink, int endColumnSink, string filePathSource,
int startLineSource, int endLineSource, int startColumnSource, int endColumnSource
where
cfg instanceof NosqlInjection::Configuration and
cfg.hasFlow(source, sink) and
not EndToEndEvaluation::isFlowExcluded(source, sink) and
sink.hasLocationInfo(filePathSink, startLineSink, startColumnSink, endLineSink, endColumnSink) and
source
.hasLocationInfo(filePathSource, startLineSource, startColumnSource, endLineSource,
endColumnSource)
select source, startLineSource, startColumnSource, endLineSource, endColumnSource, filePathSource,
sink, startLineSink, startColumnSink, endLineSink, endColumnSink, filePathSink

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