Compare commits

..

156 Commits

Author SHA1 Message Date
Andrew Eisenberg
0e53ad33f6 Actions: Add permissions block to code scanning workflow 2021-04-26 10:53:29 -07:00
Andrew Eisenberg
3670c729c0 Actions: Use the main branch of the codeql action
This commit switches to the bleeding edge, main branch of the
codeql action. This helps us test the action before merging all
of the new changes into main, which occurs roughly once a week.

If there are commits that introduce bugs in codeql-action, then
we will be more likely to catch it before releasing to the world
if we are using it in this extension.
2021-04-26 08:43:28 -07:00
Shati Patel
a09c12acfe Merge pull request #5537 from alexet/ambig-super
Docs: Update the language specification for changes to super.
2021-04-26 13:34:50 +01:00
Tamás Vajk
a7030c7fed Merge pull request #5308 from tamasvajk/feature/flow-sources-sinks
C#: Add Console.Read* to local flow sources
2021-04-23 16:36:16 +02:00
Tamás Vajk
c3058f4744 Merge pull request #5749 from tamasvajk/feature/fix-fromsource
C#: Adjust 'fromSource' to hold only on files passed to the compiler as a source file
2021-04-23 16:35:40 +02:00
Shati Patel
6f2103f312 Merge pull request #5722 from github/tamasvajk-patch-1
C#: Add Dapper to supported frameworks
2021-04-23 14:32:22 +01:00
Jonas Jensen
9b5bb95766 Merge pull request #5696 from jbj/reapply-inconsistency-workaround
Revert "Revert "C++: Work around extractor issue CPP-383""
2021-04-23 14:49:32 +02:00
Anders Schack-Mulligen
bc8c55836a Merge pull request #5743 from aschackmull/java/flow-summary-tweaks
Java/C#: Move a couple of flow summary tweaks to the shared implementation.
2021-04-23 13:46:04 +02:00
Tamas Vajk
1b4c3c7415 Fix code review findings 2021-04-23 13:44:34 +02:00
Tamás Vajk
819be43ce7 Fix alphabetical order of supported frameworks 2021-04-23 13:41:59 +02:00
Tamás Vajk
43dc9bbc94 Merge pull request #5744 from tamasvajk/feature/java-loc
Java: Introduce LoC summary metric query
2021-04-23 11:39:42 +02:00
Jonas Jensen
6de5b3021e C++: Replace Jira ticket reference with GH issue 2021-04-23 09:58:39 +02:00
Jonas Jensen
6e059ea002 C++: Remove reference to obsolete issue CPP-383 2021-04-23 09:58:15 +02:00
Shati Patel
96a4d91a6c Merge pull request #5731 from shati-patel/docs/unbind-pragmas
Docs: New "directional binding" pragmas
2021-04-23 08:37:02 +01:00
CodeQL CI
635fb4c25a Merge pull request #5685 from erik-krogh/markdownIt
Approved by asgerf
2021-04-22 14:55:31 -07:00
Taus
3e4ff9e472 Merge pull request #5742 from RasmusWL/django-3.2
Python: Add support for new features in Django 3.2
2021-04-22 17:39:02 +02:00
CodeQL CI
bdb41423e2 Merge pull request #5748 from asgerf/js/rate-limiting-fixes
Approved by erik-krogh
2021-04-22 05:56:50 -07:00
Tamas Vajk
ed42c878b0 Adjust 'fromSource' to hold only on '.cs' files 2021-04-22 14:17:16 +02:00
Tamas Vajk
b36d35bf1e Revert "C#: Adjust 'fromSource' to hold only on files passed to the compiler as a source file"
This reverts commit 1dab1590ea.
2021-04-22 14:16:10 +02:00
Mathias Vorreiter Pedersen
2b8afe55e8 Merge pull request #5747 from rdmarsh2/rdmarsh2/cpp/deprecate-return-stack-allocated-object
C++: deprecate cpp/return-stack-allocated-object
2021-04-22 11:37:07 +02:00
Owen Mansel-Chan
fea9f5f431 Merge pull request #5746 from owen-mc/java/refactor-exec-tainted
Make ExecTainted easier to extend
2021-04-22 10:14:28 +01:00
Tamas Vajk
a8a920c8f0 Add change note 2021-04-22 11:01:12 +02:00
Owen Mansel-Chan
8a01799fb8 Make imports private
Co-authored-by: Anders Schack-Mulligen <aschackmull@users.noreply.github.com>
2021-04-22 09:46:49 +01:00
Owen Mansel-Chan
4b8d4f5bbd Update docs 2021-04-22 09:30:50 +01:00
Owen Mansel-Chan
e448dcb725 Avoid bad join order
We want to avoid joining on `i` first.
2021-04-22 09:30:49 +01:00
Owen Mansel-Chan
9f1704560b Include constructors in abstract class 2021-04-22 09:30:48 +01:00
Tamas Vajk
1dab1590ea C#: Adjust 'fromSource' to hold only on files passed to the compiler as a source file 2021-04-22 10:21:28 +02:00
Tamás Vajk
9c936867fa Exclude code from XML files
Co-authored-by: yo-h <55373593+yo-h@users.noreply.github.com>
2021-04-22 09:00:31 +02:00
Tamás Vajk
a7cc9f98ef Merge pull request #5745 from tamasvajk/feature/fix-arg-default
C#: Fix special case of default argument value extraction
2021-04-22 08:58:13 +02:00
Robert Marsh
cac1bef6ea C++: deprecate cpp/return-stack-allocated-object 2021-04-21 15:17:31 -07:00
Asger Feldthaus
fe8deeaf6b JS: Autoformat 2021-04-21 23:13:57 +01:00
Asger Feldthaus
e98bfe921e JS: QLDoc 2021-04-21 22:14:50 +01:00
Asger Feldthaus
bb7934b381 JS: Change note 2021-04-21 21:20:12 +01:00
Asger Feldthaus
c113cfd8b7 JS: Autoformat 2021-04-21 21:13:07 +01:00
Rasmus Wriedt Larsen
5a9e27c6fc Merge branch 'main' into django-3.2 2021-04-21 17:15:47 +02:00
Chris Smowton
94f0a1532d Merge pull request #5682 from smowton/smowton/docs/fix-has-modifier-comment
Fix documentation of Modifier.qll
2021-04-21 15:41:29 +01:00
Tamas Vajk
a0f5e45ae9 C#: Fix special case of default argument value extraction 2021-04-21 16:34:29 +02:00
Geoffrey White
ba335089c4 Merge pull request #5601 from ihsinme/ihsinme-patch-259
CPP: Add query for CWE-691 Insufficient Control Flow Management After Refactoring The Code
2021-04-21 15:13:38 +01:00
Owen Mansel-Chan
9c72e73a82 Make ExecTainted easier to extend
To add a method that executes a command, you can now define a class
extending ExecMethod.
2021-04-21 14:55:37 +01:00
CodeQL CI
30d7f0dc98 Merge pull request #5687 from RasmusWL/inline-taint-tests
Approved by yoff
2021-04-21 06:24:12 -07:00
Asger Feldthaus
2c9a6e7bef JS: Cache function-wrapping steps in type-tracking stage 2021-04-21 13:45:58 +01:00
Tamas Vajk
e25305e3cc Java: Introduce LoC summary metric query 2021-04-21 14:27:00 +02:00
Anders Schack-Mulligen
f9599da32d Java/C#: Move a couple of flow summary tweaks to the shared implementation. 2021-04-21 14:24:15 +02:00
Rasmus Wriedt Larsen
be9cbd79d6 Python: Add change-note for Django 3.2 support 2021-04-21 13:58:34 +02:00
Rasmus Wriedt Larsen
59c6f76457 Python: Add test for new response.headers in Django
See https://docs.djangoproject.com/en/3.2/ref/request-response/#setting-header-fields
2021-04-21 13:55:22 +02:00
Rasmus Wriedt Larsen
2302c8d5fa Python: Model new alias method on django QuerySets 2021-04-21 13:52:38 +02:00
yoff
a19373ab54 Merge pull request #5727 from tausbn/python-use-localsource-in-stepsummary
Python: Use `LocalSourceNode` in `StepSummary::step`
2021-04-21 13:50:31 +02:00
Tamás Vajk
205469316c Merge pull request #5738 from tamasvajk/feature/loc
C# Add line of code metric query
2021-04-21 13:49:32 +02:00
Tamas Vajk
2a6f979ce6 C# Add line of code metric query 2021-04-21 10:42:06 +02:00
Anders Schack-Mulligen
9362ae0687 Merge pull request #5422 from tamasvajk/feature/sink-migration-ldap
Java: Migrate LDAP injection sinks to CSV format
2021-04-21 10:05:28 +02:00
Rasmus Wriedt Larsen
63a2657aef Merge branch 'main' into inline-taint-tests 2021-04-21 10:02:55 +02:00
Tom Hvitved
7080b256fb Merge pull request #5715 from hvitved/csharp/ssa/perf-tweaks
C#: A few minor SSA performance tweaks
2021-04-21 09:59:12 +02:00
Tom Hvitved
def62e8c22 Merge pull request #5718 from hvitved/csharp/hardcoded-cred-remove-cp
C#: Remove CP from `HardcodedCredentials::getCredentialSink`
2021-04-21 09:58:56 +02:00
Tom Hvitved
1ed11b297b Merge pull request #5725 from hvitved/csharp/dataflow/performance
C#: Various data-flow performance tweaks
2021-04-21 09:46:15 +02:00
yoff
ef0ea247c4 Merge pull request #5679 from tausbn/python-fix-bad-points-to-joins
Python: Fix bad points-to joins
2021-04-20 21:19:32 +02:00
Tom Hvitved
3eba5b0aac Merge pull request #5676 from hvitved/csharp/dispatch/get-a-viable-overrider-perf
C#: Speedup `DispatchMethodOrAccessorCall::getAViableOverrider()`
2021-04-20 19:57:59 +02:00
Erik Krogh Kristensen
357e1c0802 Update javascript/ql/src/semmle/javascript/frameworks/Markdown.qll
Co-authored-by: Asger F <asgerf@github.com>
2021-04-20 19:57:47 +02:00
yo-h
00137f2905 Merge pull request #5721 from github/yo-h/java-diagnostic-queries
Java: add extractor `diagnostic` queries
2021-04-20 13:36:49 -04:00
Shati Patel
98a0959784 Docs: New "directional binding" pragmas 2021-04-20 18:12:35 +01:00
Taus
890f96d9b5 Python: Prevent bad joins in TypeBackTracker
Perhaps unsurprisingly, the join orderer was eager and willing to find
the wrong join order in this predicate as well. Applying a similar
fix to the one used in `TypeTracker::step` fixes the problem.
2021-04-20 15:01:04 +00:00
Taus
c0569da65c Python: Move track/backtrack to LocalSourceNode
This is merely making explicit what was implicitly enforced. The move
to change the return type of `step` already meant that `this` and
`result` had to be `LocalSourceNode`. By moving these methods to their
rightful place, we should hopefully avoid a bit of suprising behaviour.
2021-04-20 14:39:56 +00:00
Taus
2a07441c19 Python: ModuleVariableNodes are not API uses
This caused some suprising test changes, where suddenly we had flow from
a `ModuleVariableNode` (as a `RemoteFlowSource`) to a sink. This of
course makes little sense, so instead we simply exclude these nodes as
uses in the first place.
2021-04-20 14:33:42 +00:00
Taus
7581cbade6 Python: Fix forgotten type tracker
This was the last remaining type tracker that did not use
`LocalSourceNode`.
2021-04-20 14:32:56 +00:00
Tamas Vajk
583513bafd Fix review findings 2021-04-20 16:28:47 +02:00
Asger Feldthaus
43ca8ea5f7 JS: Fix perf issue in forwardsParameter 2021-04-20 15:15:12 +01:00
Chris Smowton
a5cfdd2cfe Merge pull request #5467 from p0wn4j/groovy-execute
[Java] CWE-094: Query to detect Groovy Code Injections
2021-04-20 14:49:56 +01:00
Erik Krogh Kristensen
62dfd1fa7d improve the markdown-it model 2021-04-20 15:23:03 +02:00
Taus
38548c9acd Python: Simplify charpred for LocalSourceNode
The somewhat convoluted `comes_from_cfgnode` was originally introduced
in order to have local sources for instances of global variables. This
was needed because global variables have an implicit "scope entry" SSA
definition that flows to the first actual use of the variable (and so
would not fit the strict "has no incoming flow" definition of a local
source node).

However, a subsequent change means that we include all global variable
reads anyway, and so the old definition is no longer needed.

(See commit 3fafb47b16 for further
context.)
2021-04-20 13:19:36 +00:00
Taus
038bf612be Python: Add change note 2021-04-20 13:06:30 +00:00
Jonas Jensen
f02c86cb22 Merge pull request #5726 from MathiasVP/fix-false-positive-in-return-stack-allocated-memory-2
C++: Fix false positive in return stack allocated memory (second attempt)
2021-04-20 15:05:11 +02:00
Taus
a55b43b67e Python: Use LocalSourceNode throughout step
This commit does a lot of stuff all at once, so here are the main
highlights:

In `TypeTracker.qll`, we change `StepSummary::step` to step only between
source nodes. Because reads and writes of global variables happen in two
different (jump) steps, this requires the intermediate
`ModuleVariableNode` to _also_ be a `LocalSourceNode`, and we therefore
modify the charpred for that class accordingly. (This also means
changing a few of the tests to account for these new source nodes.)

In addition, we change `TypeTracker::step` to likewise step between
local source nodes.

Next, to enable the use of the `track` convenience method on nodes, we
add some pragmas to `TypeTracker::step` that prevent bad joins from
occurring. With this, we can eliminate all of the manual type tracker
join predicates.

Next, we observe that because `StepSummary::step` now uses `flowsTo`, it
automatically encapsulates all local-flow steps. In particular this
means we do not have to use `typePreservingStep` in `smallstep`, but can
use `jumpStep` directly. A similar observation applies to
`TypeTracker::smallstep`.

Having done this, we no longer need `typePreservingStep`, so we get rid
of it.
2021-04-20 12:59:33 +00:00
Taus
31bd701bd5 Python: Final LocalSourceNode fixes 2021-04-20 12:59:33 +00:00
Chris Smowton
9bfb0d93ca Autoformat QL 2021-04-20 13:59:09 +01:00
Rasmus Wriedt Larsen
897105de02 Merge pull request #5717 from tausbn/python-use-api-graphs-in-django
Python: Use API graphs in Django model
2021-04-20 14:57:55 +02:00
Erik Krogh Kristensen
19c5889775 use mayHaveBooleanValue 2021-04-20 14:39:54 +02:00
Erik Krogh Kristensen
13d915927b add change note 2021-04-20 14:39:54 +02:00
Erik Krogh Kristensen
7046f1a902 add taint-step for markdown-it when the HTML flag is set 2021-04-20 14:39:54 +02:00
Taus
76700d17d6 Merge pull request #5684 from RasmusWL/flask-more-taint-tests
Python: Add taint tests for .get() in flask
2021-04-20 14:08:08 +02:00
Asger Feldthaus
f8d428cb2d JS: Use function-forwarding steps when tracking rate limiters 2021-04-20 13:00:42 +01:00
Mathias Vorreiter Pedersen
93e55e2631 C++: Fix FP in cpp/return-stack-allocated-memory. 2021-04-20 13:58:12 +02:00
Mathias Vorreiter Pedersen
1797b6c7f9 C++: Add FP test from the work on smart pointers in dataflow. 2021-04-20 13:54:57 +02:00
Asger Feldthaus
581f4ed757 JS: Generalize handling of route handler wrapper functions 2021-04-20 12:46:40 +01:00
Chris Smowton
0ec3ee29e4 Style last use of SecureASTCustomizer 2021-04-20 12:44:49 +01:00
Hayk Andriasyan
bb58a50503 Update GroovyInjection.qhelp 2021-04-20 15:41:58 +04:00
p0wn4j
f2de440886 [Java] CWE-094: Query to detect Groovy Code Injections 2021-04-20 19:18:24 +04:00
Jonas Jensen
d4fdd50e2c Merge pull request #5723 from MathiasVP/cleanup-smart-ptr-model
C++: Simplify smart pointer model
2021-04-20 13:25:02 +02:00
Tom Hvitved
dd1bb18938 C#: Various data-flow performance tweaks
- Cache `DataFlowCall::getEnclosingCallable()`.
- Cache `ParameterNode`.
- Cache `ArgumentNode`.
- Force proper join-orders for uses of `getNodeType()`.
- Inline `localFlow` to prevent calculating full TC.
2021-04-20 11:56:25 +02:00
Tom Hvitved
1f9239089f Merge pull request #5695 from hvitved/csharp/dispose-not-called-on-exc-perf
C#: Improve performance of `DisposeNotCalledOnException.ql`
2021-04-20 11:52:18 +02:00
Tom Hvitved
b2a7a3ed30 Merge pull request #5674 from hvitved/csharp/ssa/call-graph-perf
C#: Improve performance of `SsaImpl::CallGraph::SimpleDelegateAnalysis`
2021-04-20 11:51:52 +02:00
Geoffrey White
2b7e599dc4 Merge pull request #5703 from MathiasVP/improve-access-of-memory-location-after-end-of-buffer-using-strncat
C++: Improve cpp/access-memory-location-after-end-buffer-strncat
2021-04-20 10:44:24 +01:00
Mathias Vorreiter Pedersen
61d4d17225 C++: Simplify smart pointer model and accept test changes. 2021-04-20 09:57:58 +02:00
Tamás Vajk
408954e4d8 C#: Add Dapper to supported frameworks 2021-04-20 09:30:47 +02:00
yo-h
87cd72496c Java: add extractor diagnostic queries 2021-04-19 15:34:16 -04:00
yo-h
cb524b6c19 Merge pull request #5611 from github/yo-h/java16
Java: adjust test `options` for JDK 16 upgrade
2021-04-19 15:12:23 -04:00
Taus
bc6685aa3f Python: Fix typo
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
2021-04-19 19:57:35 +02:00
Anders Schack-Mulligen
5458c02cc2 Merge pull request #5456 from aschackmull/java/adopt-flow-summary
Java: Use shared flow summary library for CSV models.
2021-04-19 16:21:10 +02:00
Anders Schack-Mulligen
33db0c13cd Merge pull request #5689 from github/aeisenberg/rework-staleness
Actions: Change staleness calculation
2021-04-19 15:57:41 +02:00
Tom Hvitved
9128ec72ad C#: A few minor SSA performance tweaks 2021-04-19 15:51:14 +02:00
Anders Schack-Mulligen
80eb0a2df6 Apply suggestions from code review
Co-authored-by: Chris Smowton <smowton@github.com>
2021-04-19 15:45:58 +02:00
CodeQL CI
437bba1e3c Merge pull request #5716 from erik-krogh/vscodeRegress
Approved by esbena
2021-04-19 06:30:02 -07:00
Tom Hvitved
15e4b7f95d C#: Remove CP from HardcodedCredentials::getCredentialSink 2021-04-19 15:03:11 +02:00
Rasmus Wriedt Larsen
d607c13ab6 Python: Taint tests: include elment for forgotten MISSING 2021-04-19 15:01:42 +02:00
Rasmus Wriedt Larsen
9585390941 Python: Taint tests, report error location first
To better match the standard output from inline expectation tests
2021-04-19 14:59:47 +02:00
Rasmus Wriedt Larsen
b2cb284ff2 Python: Add more examples of what is ok with new taint tests 2021-04-19 14:56:20 +02:00
Anders Schack-Mulligen
7d84cfacef Java: Add MapKeyContent and MapValueContent. 2021-04-19 14:06:27 +02:00
Anders Schack-Mulligen
39862740e0 Java: Convert support for fluent interfaces. 2021-04-19 14:06:27 +02:00
Anders Schack-Mulligen
579c955892 Java: Adjust some tests. 2021-04-19 14:06:27 +02:00
Anders Schack-Mulligen
175c71221a Java: Adjust some test output with more edges/nodes. 2021-04-19 14:06:27 +02:00
Anders Schack-Mulligen
60965b0d8c Java: Adjust some csv models. 2021-04-19 14:02:19 +02:00
Anders Schack-Mulligen
a27dac029f Java: Use shared flow summary library for csv models. 2021-04-19 14:02:19 +02:00
Chris Smowton
36abf8733e Merge pull request #5714 from aschackmull/java/add-misc-qltests
Java: Add a few qltests
2021-04-19 13:00:10 +01:00
Taus
9acc71a7cb Python: Get rid of all _attr methods in Django.qll 2021-04-19 11:54:10 +00:00
Erik Krogh Kristensen
9e6f28e335 fix bad join order in Xss.qll 2021-04-19 13:17:49 +02:00
Anders Schack-Mulligen
29aec0d770 Java: Adjust expected output. 2021-04-19 13:16:46 +02:00
Anders Schack-Mulligen
c5193cf03f Apply suggestions from code review 2021-04-19 13:14:56 +02:00
Anders Schack-Mulligen
06514159be Java: Add XXE tests. 2021-04-19 10:58:21 +02:00
Anders Schack-Mulligen
daad62c4e0 Java: Add TaintedPath test. 2021-04-19 10:07:03 +02:00
Jonas Jensen
1ab75eb6f4 Merge pull request #5708 from github/fix-id-in-JsonpInjection-1
Java: Fix id in experimental JsonpInjection.ql query
2021-04-19 08:23:34 +02:00
yoff
118840dad4 Merge pull request #5690 from tausbn/python-disallow-post-update-nodes-as-local-source-nodes
Python: Disallow `PostUpdateNode` as `LocalSourceNode`
2021-04-19 06:56:11 +02:00
ihsinme
c2d97b98e2 Merge branch 'main' into ihsinme-patch-259 2021-04-18 21:01:56 +03:00
Mathias Vorreiter Pedersen
e36b42a03f Java: Fix invalid id in experimental query
The invalid id broke CI here: https://github.com/github/codeql/pull/5703 (see https://github.slack.com/archives/CPSEA0G22/p1618602834224600)
2021-04-17 09:47:15 +02:00
Taus
f3661c34ee Python: Clean up Django models using API graphs
First sweep. Takes care of most of the models.
2021-04-16 19:53:36 +00:00
Mathias Vorreiter Pedersen
95742aec69 C++: Accept test changes for the other experimental query in the directory. This is only a change in line numbers. 2021-04-16 21:29:17 +02:00
Mathias Vorreiter Pedersen
64f8316a6d C++: Tidy up the ql file and accept test changes. 2021-04-16 21:22:13 +02:00
Mathias Vorreiter Pedersen
1e327289b2 C++: Add false negative test. 2021-04-16 18:38:51 +02:00
Mathias Vorreiter Pedersen
50abb6e3a1 C++: Cleanup test.c 2021-04-16 17:32:44 +02:00
Jonas Jensen
f8d45f04ed Revert "Revert "C++: Work around extractor issue CPP-383""
**Revert the revert** of the workaround for CFG issues when a
`FunctionCall` has a `getTarget` that does not exist. While we've fixed
the main cause of the problem, it can apparently still happen in rare
cases as a result of extractor crashes.

This reverts commit ee5eaef5e4.
2021-04-16 16:44:58 +02:00
Tom Hvitved
40b74167e0 C#: Improve performance of DisposeNotCalledOnException.ql 2021-04-16 14:34:16 +02:00
Taus
92b4eb7f02 Python: Cleanup and more explanation
Goes into some detail about the intended semantics of local source nodes
and `flowsTo`.
2021-04-16 11:54:20 +00:00
Tom Hvitved
946fcf1c82 C#: Speedup DispatchMethodOrAccessorCall::getAViableOverrider()
In addition to improved performance, the analysis no longer applies a closed-world
assumption to type parameters. That is, if the type of a receiver is a type parameter,
then the call may target any method of a compatible receiver type, not just the
types that actually instantiate the type parameter.
2021-04-16 10:43:17 +02:00
Taus
451d36dc97 Python: Allow _some_ PostUpdateNodes
Specifically, allow the ones arising from calls, but not reads or
writes. This should fix the tests.
2021-04-15 21:26:12 +00:00
Taus
c9c8259ed0 Python: Disallow PostUpdateNode as LocalSourceNode
Previously, in cases like

```python
def foo(x):
    x.bar()
    x.baz()
    x.quux()
```

we would have flow from the first `x` to each use _and_ flow from the
post-update node for each method call to each subsequent use, and all
of these would be `LocalSourceNode`s. For large functions with the above
pattern, this would lead to a quadratic blowup in `hasLocalSource`.

With this commit, only the first of these will count as a
`LocalSourceNode`, and the blowup disappears.
2021-04-15 17:56:14 +00:00
Andrew Eisenberg
5d827b6fc8 Actions: Change staleness calculation
Calculate staleness on issues that have the
`Stale` label. Leave all other issues untouched.
2021-04-15 10:14:13 -07:00
Rasmus Wriedt Larsen
3e7dc12246 Python: Port taint tests to use inline expectations
The meat of this PR is described in the new python/ql/test/experimental/meta/InlineTaintTest.qll file:

> Defines a InlineExpectationsTest for checking whether any arguments in
> `ensure_tainted` and `ensure_not_tainted` calls are tainted.
>
> Also defines query predicates to ensure that:
> - if any arguments to `ensure_not_tainted` are tainted, their annotation is marked with `SPURIOUS`.
> - if any arguments to `ensure_tainted` are not tainted, their annotation is marked with `MISSING`.
>
> The functionality of this module is tested in `ql/test/experimental/meta/inline-taint-test-demo`.
2021-04-15 18:00:33 +02:00
Rasmus Wriedt Larsen
b359205d17 Python: Add taint tests for .get() in flask 2021-04-15 14:53:44 +02:00
Tom Hvitved
0f24db8759 C#: Improve performance of SsaImpl::CallGraph::SimpleDelegateAnalysis 2021-04-15 11:25:27 +02:00
Chris Smowton
bd3b3178ba Fix documentation of Modifier.qll 2021-04-15 09:16:51 +01:00
ihsinme
b30ae3980c Update InsufficientControlFlowManagementAfterRefactoringTheCode.ql 2021-04-14 20:48:20 +03:00
Taus
897d12420b Python: Prevent bad join in isinstanceEvaluatesTo
In some cases, we were joining the result of `val.getClass()` against
the first argument of `Types::improperSubclass` before filtering out the
vast majority of tuples by the call to `isinstance_call`.

To fix this, we let `isinstance_call` take care of figuring out the
class of the value being tested. As a bonus, this cleans up the only
other place where `isinstance_call` is used, where we _also_ want to
know the class of the value being tested in the `isinstance` call.
2021-04-14 16:49:12 +00:00
Taus
a7fcf52267 Python: Fix bad join in total_cost
The recent change to `appliesTo` lead to a perturbation in the join
order of this predicate, which resulted in a cartesian product between
`call` and `ctx` being created (before being filtered by `appliesTo`).

By splitting the intermediate result into its own helper predicate,
suitably marked to prevent inlining/magic, we prevent this from
happening again.
2021-04-14 15:36:01 +00:00
ihsinme
58d5ad48d5 Update InsufficientControlFlowManagementAfterRefactoringTheCode.ql 2021-04-12 17:00:34 +03:00
ihsinme
d7c14775bf Update InsufficientControlFlowManagementAfterRefactoringTheCode.qhelp 2021-04-12 16:56:48 +03:00
Tamas Vajk
b4d35b52c3 C#: Add Console.Read* to local flow sources 2021-04-12 14:19:17 +02:00
ihsinme
feb3a8deb1 Update InsufficientControlFlowManagementAfterRefactoringTheCode.expected 2021-04-12 08:23:41 +03:00
ihsinme
6924c6c51c Update test.c 2021-04-12 08:23:06 +03:00
ihsinme
3da88f2103 Update InsufficientControlFlowManagementAfterRefactoringTheCode.c 2021-04-12 08:15:36 +03:00
ihsinme
17d1c77a14 Update InsufficientControlFlowManagementAfterRefactoringTheCode.ql 2021-04-12 08:14:17 +03:00
yo-h
4f2060f96b Merge commit '2d618d6b928d8b76ac8033b3b63d9bde71caa325' into yo-h/java16 2021-04-11 23:55:33 -04:00
Tamas Vajk
53daa7c436 Java: Migrate LDAP injection sinks to CSV format 2021-04-09 09:15:47 +02:00
ihsinme
3d117243e4 Update test.c 2021-04-08 22:05:31 +03:00
ihsinme
cbf158ea6b Add files via upload 2021-04-07 13:12:30 +03:00
ihsinme
36de496d47 Add files via upload 2021-04-07 13:12:29 +03:00
yo-h
cc63563a88 Merge remote-tracking branch 'upstream-public/main' into yo-h/java16 2021-04-06 13:16:02 -04:00
Alexander Eyers-Taylor
b21672c81c Apply suggestions from code review
Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com>
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
2021-03-26 11:15:46 +00:00
alexet
2576c86ebf Docs: Update the language specification for changes to super. 2021-03-25 18:16:13 +00:00
yo-h
0200aedc2e Java 16: adjust test options 2021-03-21 12:55:25 -04:00
218 changed files with 3986 additions and 2684 deletions

View File

@@ -15,16 +15,16 @@ jobs:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `stale` label in order to avoid having this issue closed in 7 days.'
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'
close-issue-message: 'This issue was closed because it has been inactive for 7 days.'
days-before-stale: 14
days-before-close: 7
only-labels: question
only-labels: awaiting-response
# do not mark PRs as stale
days-before-pr-stale: -1
days-before-pr-close: -1
# Uncomment for dry-run
# debug-only: true
# operations-per-run: 1000

View File

@@ -19,13 +19,18 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
security_events: write
pull_requests: read
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@main
# Override language selection by uncommenting this and choosing your languages
with:
languages: csharp
@@ -34,7 +39,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@main
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -48,4 +53,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@main

View File

@@ -0,0 +1,2 @@
codescanning
* The 'Pointer to stack object used as return value' (cpp/return-stack-allocated-object) query has been deprecated, and any uses should be replaced with `Returning stack-allocated memory` (cpp/return-stack-allocated-memory).

View File

@@ -7,6 +7,8 @@
* @tags reliability
* security
* external/cwe/cwe-562
* @deprecated This query is not suitable for production use and has been deprecated. Use
* cpp/return-stack-allocated-memory instead.
*/
import semmle.code.cpp.pointsto.PointsTo

View File

@@ -13,6 +13,7 @@
import cpp
import semmle.code.cpp.dataflow.EscapesTree
import semmle.code.cpp.models.interfaces.PointerWrapper
import semmle.code.cpp.dataflow.DataFlow
/**
@@ -39,6 +40,10 @@ predicate hasNontrivialConversion(Expr e) {
e instanceof ParenthesisExpr
)
or
// A smart pointer can be stack-allocated while the data it points to is heap-allocated.
// So we exclude such "conversions" from this predicate.
e = any(PointerWrapper wrapper).getAnUnwrapperFunction().getACallToThisFunction()
or
hasNontrivialConversion(e.getConversion())
}

View File

@@ -0,0 +1,17 @@
while(flagsLoop)
{
...
if(flagsIf) break;
...
}while(flagsLoop); // BAD: when exiting through `break`, it is possible to get into an eternal loop.
...
while(flagsLoop)
{
...
if(flagsIf) break;
...
} // GOOD: correct cycle
...
if(intA+intB) return 1; // BAD: possibly no comparison
...
if(intA+intB>intC) return 1; // GOOD: correct comparison

View File

@@ -0,0 +1,28 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>In some situations, after code refactoring, parts of the old constructs may remain. They are correctly accepted by the compiler, but can critically affect program execution. For example, if you switch from `do {...} while ();` to `while () {...}` forgetting to remove the old construct completely, you get `while(){...}while();` which may be vulnerable. These code snippets look suspicious and require the developer's attention.</p>
</overview>
<recommendation>
<p>We recommend that you use more explicit code transformations.</p>
</recommendation>
<example>
<p>The following example demonstrates the erroneous and corrected sections of the code.</p>
<sample src="InsufficientControlFlowManagementAfterRefactoringTheCode.c" />
</example>
<references>
<li>
CWE Common Weakness Enumeration:
<a href="https://cwe.mitre.org/data/definitions/691.html"> CWE-691: Insufficient Control Flow Management</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,119 @@
/**
* @name Errors After Refactoring
* @description --In some situations, after code refactoring, parts of the old constructs may remain.
* --They are correctly accepted by the compiler, but can critically affect program execution.
* --For example, if you switch from `do {...} while ();` to `while () {...}` with errors, you run the risk of running out of resources.
* --These code snippets look suspicious and require the developer's attention.
* @kind problem
* @id cpp/errors-after-refactoring
* @problem.severity warning
* @precision medium
* @tags correctness
* security
* external/cwe/cwe-691
*/
import cpp
import semmle.code.cpp.valuenumbering.HashCons
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
/**
* Using `while` directly after the body of another` while`.
*/
class UsingWhileAfterWhile extends WhileStmt {
/**
* Using a loop call after another loop has finished running can result in an eternal loop.
* For example, perhaps as a result of refactoring, the `do ... while ()` loop was incorrectly corrected.
* Even in the case of deliberate use of such an expression, it is better to correct it.
*/
UsingWhileAfterWhile() {
exists(WhileStmt wh1 |
wh1.getStmt().getAChild*().(BreakStmt).(ControlFlowNode).getASuccessor().getASuccessor() =
this and
hashCons(wh1.getCondition()) = hashCons(this.getCondition()) and
this.getStmt() instanceof EmptyStmt
)
or
exists(ForStmt fr1 |
fr1.getStmt().getAChild*().(BreakStmt).(ControlFlowNode).getASuccessor().getASuccessor() =
this and
hashCons(fr1.getCondition()) = hashCons(this.getCondition()) and
this.getStmt() instanceof EmptyStmt
)
}
}
/**
* Using arithmetic in a condition.
*/
class UsingArithmeticInComparison extends BinaryArithmeticOperation {
/**
* Using arithmetic operations in a comparison operation can be dangerous.
* For example, part of the comparison may have been lost as a result of refactoring.
* Even if you deliberately use such an expression, it is better to add an explicit comparison.
*/
UsingArithmeticInComparison() {
this.getParent*() instanceof IfStmt and
not this.getAChild*().isConstant() and
not this.getParent*() instanceof Call and
not this.getParent*() instanceof AssignExpr and
not this.getParent*() instanceof ArrayExpr and
not this.getParent*() instanceof RemExpr and
not this.getParent*() instanceof AssignBitwiseOperation and
not this.getParent*() instanceof AssignArithmeticOperation and
not this.getParent*() instanceof EqualityOperation and
not this.getParent*() instanceof RelationalOperation
}
/** Holds when the expression is inside the loop body. */
predicate insideTheLoop() { exists(Loop lp | lp.getStmt().getAChild*() = this.getParent*()) }
/** Holds when the expression is used in binary operations. */
predicate workingWithValue() {
this.getParent*() instanceof BinaryBitwiseOperation or
this.getParent*() instanceof NotExpr
}
/** Holds when the expression contains a pointer. */
predicate workingWithPointer() {
this.getAChild*().getFullyConverted().getType() instanceof DerivedType
}
/** Holds when a null comparison expression exists. */
predicate compareWithZero() {
exists(Expr exp |
exp instanceof ComparisonOperation and
(
globalValueNumber(exp.getAChild*()) = globalValueNumber(this) or
hashCons(exp.getAChild*()) = hashCons(this)
) and
(
exp.(ComparisonOperation).getLeftOperand().getValue() = "0" or
exp.(ComparisonOperation).getRightOperand().getValue() = "0"
)
)
}
/** Holds when a comparison expression exists. */
predicate compareWithOutZero() {
exists(Expr exp |
exp instanceof ComparisonOperation and
(
globalValueNumber(exp.getAChild*()) = globalValueNumber(this) or
hashCons(exp.getAChild*()) = hashCons(this)
)
)
}
}
from Expr exp
where
exp instanceof UsingArithmeticInComparison and
not exp.(UsingArithmeticInComparison).workingWithValue() and
not exp.(UsingArithmeticInComparison).workingWithPointer() and
not exp.(UsingArithmeticInComparison).insideTheLoop() and
not exp.(UsingArithmeticInComparison).compareWithZero() and
exp.(UsingArithmeticInComparison).compareWithOutZero()
or
exists(WhileStmt wst | wst instanceof UsingWhileAfterWhile and exp = wst.getCondition())
select exp, "this expression needs your attention"

View File

@@ -11,54 +11,32 @@
*/
import cpp
import semmle.code.cpp.models.implementations.Strcat
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
/**
* A call to `strncat` of the form `strncat(buff, str, someExpr - strlen(buf))`, for some expression `someExpr` equal to `sizeof(buff)`.
* Holds if `call` is a call to `strncat` such that `sizeArg` and `destArg` are the size and
* destination arguments, respectively.
*/
class WrongCallStrncat extends FunctionCall {
Expr leftsomeExpr;
WrongCallStrncat() {
this.getTarget().hasGlobalOrStdName("strncat") and
// the expression of the first argument in `strncat` and `strnlen` is identical
globalValueNumber(this.getArgument(0)) =
globalValueNumber(this.getArgument(2).(SubExpr).getRightOperand().(StrlenCall).getStringExpr()) and
// using a string constant often speaks of manually calculating the length of the required buffer.
(
not this.getArgument(1) instanceof StringLiteral and
not this.getArgument(1) instanceof CharLiteral
) and
// for use in predicates
leftsomeExpr = this.getArgument(2).(SubExpr).getLeftOperand()
}
/**
* Holds if the left side of the expression `someExpr` equal to `sizeof(buf)`.
*/
predicate isExpressionEqualSizeof() {
// the left side of the expression `someExpr` is `sizeof(buf)`.
globalValueNumber(this.getArgument(0)) =
globalValueNumber(leftsomeExpr.(SizeofExprOperator).getExprOperand())
or
// value of the left side of the expression `someExpr` equal `sizeof(buf)` value, and `buf` is array.
leftsomeExpr.getValue().toInt() = this.getArgument(0).getType().getSize()
}
/**
* Holds if the left side of the expression `someExpr` equal to variable containing the length of the memory allocated for the buffer.
*/
predicate isVariableEqualValueSizegBuffer() {
// the left side of expression `someExpr` is the variable that was used in the function of allocating memory for the buffer`.
exists(AllocationExpr alc |
leftsomeExpr.(VariableAccess).getTarget() =
alc.(FunctionCall).getArgument(0).(VariableAccess).getTarget()
)
}
predicate interestringCallWithArgs(Call call, Expr sizeArg, Expr destArg) {
exists(StrcatFunction strcat |
strcat = call.getTarget() and
sizeArg = call.getArgument(strcat.getParamSize()) and
destArg = call.getArgument(strcat.getParamDest())
)
}
from WrongCallStrncat sc
from FunctionCall call, Expr sizeArg, Expr destArg, SubExpr sub, int n
where
sc.isExpressionEqualSizeof() or
sc.isVariableEqualValueSizegBuffer()
select sc, "if the used buffer is full, writing out of the buffer is possible"
interestringCallWithArgs(call, sizeArg, destArg) and
// The destination buffer is an array of size n
destArg.getUnspecifiedType().(ArrayType).getSize() = n and
// The size argument is equivalent to a subtraction
globalValueNumber(sizeArg).getAnExpr() = sub and
// ... where the left side of the subtraction is the constant n
globalValueNumber(sub.getLeftOperand()).getAnExpr().getValue().toInt() = n and
// ... and the right side of the subtraction is a call to `strlen` where the argument is the
// destination buffer.
globalValueNumber(sub.getRightOperand()).getAnExpr().(StrlenCall).getStringExpr() =
globalValueNumber(destArg).getAnExpr()
select call, "Possible out-of-bounds write due to incorrect size argument."

View File

@@ -1307,7 +1307,8 @@ private predicate conditionJumps(Expr test, boolean truth, Node n2, Pos p2) {
)
}
// Factored out for performance. See QL-796.
// Pulled out for performance. See
// https://github.com/github/codeql-coreql-team/issues/1044.
private predicate normalGroupMemberBaseCase(Node memberNode, Pos memberPos, Node atNode) {
memberNode = atNode and
memberPos.isAt() and

View File

@@ -104,9 +104,43 @@ private predicate loopConditionAlwaysUponEntry(ControlFlowNode loop, Expr condit
)
}
/**
* This relation is the same as the `el instanceof Function`, only obfuscated
* so the optimizer will not understand that any `FunctionCall.getTarget()`
* should be in this relation.
*/
pragma[noinline]
private predicate isFunction(Element el) {
el instanceof Function
or
el.(Expr).getParent() = el
}
/**
* Holds if `fc` is a `FunctionCall` with no return value for `getTarget`. This
* can happen in case of rare database inconsistencies.
*/
pragma[noopt]
private predicate callHasNoTarget(@funbindexpr fc) {
exists(Function f |
funbind(fc, f) and
not isFunction(f)
)
}
// Pulled out for performance. See
// https://github.com/github/codeql-coreql-team/issues/1044.
private predicate potentiallyReturningFunctionCall_base(FunctionCall fc) {
fc.isVirtual()
or
callHasNoTarget(fc)
}
/** A function call that *may* return; if in doubt, we assume it may. */
private predicate potentiallyReturningFunctionCall(FunctionCall fc) {
potentiallyReturningFunction(fc.getTarget()) or fc.isVirtual()
potentiallyReturningFunctionCall_base(fc)
or
potentiallyReturningFunction(fc.getTarget())
}
/** A function that *may* return; if in doubt, we assume it may. */

View File

@@ -1271,7 +1271,8 @@ private predicate convparents(Expr child, int idx, Element parent) {
)
}
// Pulled out for performance. See QL-796.
// Pulled out for performance. See
// https://github.com/github/codeql-coreql-team/issues/1044.
private predicate hasNoConversions(Expr e) { not e.hasConversion() }
/**

View File

@@ -42,7 +42,8 @@ IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
*/
predicate isIRConstant(Expr expr) { exists(expr.getValue()) }
// Pulled out to work around QL-796
// Pulled out for performance. See
// https://github.com/github/codeql-coreql-team/issues/1044.
private predicate isOrphan(Expr expr) { not exists(getRealParent(expr)) }
/**

View File

@@ -18,20 +18,20 @@ private class UniqueOrSharedPtr extends Class, PointerWrapper {
}
/** Any function that unwraps a pointer wrapper class to reveal the underlying pointer. */
private class PointerWrapperDataFlow extends DataFlowFunction {
PointerWrapperDataFlow() {
private class PointerWrapperFlow extends TaintFunction, DataFlowFunction {
PointerWrapperFlow() {
this = any(PointerWrapper wrapper).getAnUnwrapperFunction() and
not this.getUnspecifiedType() instanceof ReferenceType
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierAddress() and output.isReturnValue()
or
input.isQualifierObject() and output.isReturnValueDeref()
or
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isReturnValueDeref() and
output.isQualifierObject()
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierObject() and output.isReturnValue()
}
}
/**

View File

@@ -0,0 +1,4 @@
| test.c:15:6:15:16 | ... + ... | this expression needs your attention |
| test.c:17:17:17:27 | ... + ... | this expression needs your attention |
| test.c:22:10:22:15 | ... > ... | this expression needs your attention |
| test.c:26:10:26:15 | ... > ... | this expression needs your attention |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-691/InsufficientControlFlowManagementAfterRefactoringTheCode.ql

View File

@@ -12,14 +12,18 @@ void workFunction_0(char *s) {
void workFunction_1(char *s) {
int intA,intB;
if(intA + intB) return; // BAD [NOT DETECTED]
if(intA + intB) return; // BAD
if(intA + intB>4) return; // GOOD
if(intA>0 && (intA + intB)) return; // BAD [NOT DETECTED]
if(intA>0 && (intA + intB)) return; // BAD
while(intA>0)
{
if(intB - intA<10) break;
intA--;
}while(intA>0); // BAD [NOT DETECTED]
}while(intA>0); // BAD
for(intA=100; intA>0; intA--)
{
if(intB - intA<10) break;
}while(intA>0); // BAD
while(intA>0)
{
if(intB - intA<10) break;

View File

@@ -1,9 +1,9 @@
| test.c:42:3:42:24 | ... = ... | potential unsafe or redundant assignment. |
| test.c:43:3:43:40 | ... = ... | potential unsafe or redundant assignment. |
| test.c:44:3:44:40 | ... = ... | potential unsafe or redundant assignment. |
| test.c:45:3:45:44 | ... = ... | potential unsafe or redundant assignment. |
| test.c:46:3:46:44 | ... = ... | potential unsafe or redundant assignment. |
| test.c:47:3:47:48 | ... = ... | potential unsafe or redundant assignment. |
| test.c:48:3:48:48 | ... = ... | potential unsafe or redundant assignment. |
| test.c:49:3:49:50 | ... = ... | potential unsafe or redundant assignment. |
| test.c:50:3:50:50 | ... = ... | potential unsafe or redundant assignment. |
| test.c:54:3:54:24 | ... = ... | potential unsafe or redundant assignment. |
| test.c:55:3:55:40 | ... = ... | potential unsafe or redundant assignment. |
| test.c:56:3:56:44 | ... = ... | potential unsafe or redundant assignment. |
| test.c:57:3:57:44 | ... = ... | potential unsafe or redundant assignment. |
| test.c:58:3:58:48 | ... = ... | potential unsafe or redundant assignment. |
| test.c:59:3:59:48 | ... = ... | potential unsafe or redundant assignment. |
| test.c:60:3:60:52 | ... = ... | potential unsafe or redundant assignment. |
| test.c:61:3:61:50 | ... = ... | potential unsafe or redundant assignment. |
| test.c:62:3:62:54 | ... = ... | potential unsafe or redundant assignment. |

View File

@@ -1,3 +1,5 @@
| test.c:4:3:4:9 | call to strncat | if the used buffer is full, writing out of the buffer is possible |
| test.c:11:3:11:9 | call to strncat | if the used buffer is full, writing out of the buffer is possible |
| test.c:19:3:19:9 | call to strncat | if the used buffer is full, writing out of the buffer is possible |
| test.c:8:3:8:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |
| test.c:9:3:9:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |
| test.c:17:3:17:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |
| test.c:18:3:18:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |
| test.c:46:3:46:9 | call to strncat | Possible out-of-bounds write due to incorrect size argument. |

View File

@@ -1,70 +1,84 @@
void workFunction_0(char *s) {
char * strncat(char*, const char*, unsigned);
unsigned strlen(const char*);
void* malloc(unsigned);
void strncat_test1(char *s) {
char buf[80];
strncat(buf, s, sizeof(buf)-strlen(buf)-1); // GOOD
strncat(buf, s, sizeof(buf)-strlen(buf)); // BAD
strncat(buf, "fix", sizeof(buf)-strlen(buf)); // BAD [NOT DETECTED]
strncat(buf, s, sizeof(buf) - strlen(buf) - 1); // GOOD
strncat(buf, s, sizeof(buf) - strlen(buf)); // BAD
strncat(buf, "fix", sizeof(buf)-strlen(buf)); // BAD
}
void workFunction_1(char *s) {
#define MAX_SIZE 80
void strncat_test2(char *s) {
char buf[MAX_SIZE];
strncat(buf, s, MAX_SIZE-strlen(buf)-1); // GOOD
strncat(buf, s, MAX_SIZE-strlen(buf)); // BAD
strncat(buf, "fix", MAX_SIZE-strlen(buf)); // BAD [NOT DETECTED]
strncat(buf, s, MAX_SIZE - strlen(buf) - 1); // GOOD
strncat(buf, s, MAX_SIZE - strlen(buf)); // BAD
strncat(buf, "fix", MAX_SIZE - strlen(buf)); // BAD
}
void workFunction_2_0(char *s) {
char * buf;
int len=80;
buf = (char *) malloc(len);
strncat(buf, s, len-strlen(buf)-1); // GOOD
strncat(buf, s, len-strlen(buf)); // BAD
strncat(buf, "fix", len-strlen(buf)); // BAD [NOT DETECTED]
void strncat_test3(char *s) {
int len = 80;
char* buf = (char *) malloc(len);
strncat(buf, s, len - strlen(buf) - 1); // GOOD
strncat(buf, s, len - strlen(buf)); // BAD [NOT DETECTED]
strncat(buf, "fix", len - strlen(buf)); // BAD [NOT DETECTED]
}
void workFunction_2_1(char *s) {
char * buf;
int len=80;
buf = (char *) malloc(len+1);
strncat(buf, s, len-strlen(buf)-1); // GOOD
strncat(buf, s, len-strlen(buf)); // GOOD
void strncat_test4(char *s) {
int len = 80;
char* buf = (char *) malloc(len + 1);
strncat(buf, s, len - strlen(buf) - 1); // GOOD
strncat(buf, s, len - strlen(buf)); // GOOD
}
struct buffers
{
unsigned char buff1[50];
unsigned char *buff2;
unsigned char array[50];
unsigned char *pointer;
} globalBuff1,*globalBuff2,globalBuff1_c,*globalBuff2_c;
void strncat_test5(char* s, struct buffers* buffers) {
unsigned len_array = strlen(buffers->array);
unsigned max_size = sizeof(buffers->array);
unsigned free_size = max_size - len_array;
strncat(buffers->array, s, free_size); // BAD
}
void badFunc0(){
void strlen_test1(){
unsigned char buff1[12];
struct buffers buffAll;
struct buffers * buffAll1;
buff1[strlen(buff1)]=0; // BAD
buffAll.buff1[strlen(buffAll.buff1)]=0; // BAD
buffAll.buff2[strlen(buffAll.buff2)]=0; // BAD
buffAll1->buff1[strlen(buffAll1->buff1)]=0; // BAD
buffAll1->buff2[strlen(buffAll1->buff2)]=0; // BAD
globalBuff1.buff1[strlen(globalBuff1.buff1)]=0; // BAD
globalBuff1.buff2[strlen(globalBuff1.buff2)]=0; // BAD
globalBuff2->buff1[strlen(globalBuff2->buff1)]=0; // BAD
globalBuff2->buff2[strlen(globalBuff2->buff2)]=0; // BAD
buffAll.array[strlen(buffAll.array)]=0; // BAD
buffAll.pointer[strlen(buffAll.pointer)]=0; // BAD
buffAll1->array[strlen(buffAll1->array)]=0; // BAD
buffAll1->pointer[strlen(buffAll1->pointer)]=0; // BAD
globalBuff1.array[strlen(globalBuff1.array)]=0; // BAD
globalBuff1.pointer[strlen(globalBuff1.pointer)]=0; // BAD
globalBuff2->array[strlen(globalBuff2->array)]=0; // BAD
globalBuff2->pointer[strlen(globalBuff2->pointer)]=0; // BAD
}
void noBadFunc0(){
void strlen_test2(){
unsigned char buff1[12],buff1_c[12];
struct buffers buffAll,buffAll_c;
struct buffers * buffAll1,*buffAll1_c;
buff1[strlen(buff1_c)]=0; // GOOD
buffAll.buff1[strlen(buffAll_c.buff1)]=0; // GOOD
buffAll.buff2[strlen(buffAll.buff1)]=0; // GOOD
buffAll1->buff1[strlen(buffAll1_c->buff1)]=0; // GOOD
buffAll1->buff2[strlen(buffAll1->buff1)]=0; // GOOD
globalBuff1.buff1[strlen(globalBuff1_c.buff1)]=0; // GOOD
globalBuff1.buff2[strlen(globalBuff1.buff1)]=0; // GOOD
globalBuff2->buff1[strlen(globalBuff2_c->buff1)]=0; // GOOD
globalBuff2->buff2[strlen(globalBuff2->buff1)]=0; // GOOD
buffAll.array[strlen(buffAll_c.array)]=0; // GOOD
buffAll.pointer[strlen(buffAll.array)]=0; // GOOD
buffAll1->array[strlen(buffAll1_c->array)]=0; // GOOD
buffAll1->pointer[strlen(buffAll1->array)]=0; // GOOD
globalBuff1.array[strlen(globalBuff1_c.array)]=0; // GOOD
globalBuff1.pointer[strlen(globalBuff1.array)]=0; // GOOD
globalBuff2->array[strlen(globalBuff2_c->array)]=0; // GOOD
globalBuff2->pointer[strlen(globalBuff2->array)]=0; // GOOD
}
void goodFunc0(){
void strlen_test3(){
unsigned char buffer[12];
int i;
for(i = 0; i < 6; i++)

View File

@@ -3275,11 +3275,11 @@
| smart_pointer.cpp:51:30:51:50 | call to make_shared | smart_pointer.cpp:52:10:52:10 | p | |
| smart_pointer.cpp:51:52:51:57 | call to source | smart_pointer.cpp:51:30:51:50 | call to make_shared | TAINT |
| smart_pointer.cpp:52:10:52:10 | p | smart_pointer.cpp:52:12:52:14 | call to get | |
| smart_pointer.cpp:52:12:52:14 | ref arg call to get | smart_pointer.cpp:52:10:52:10 | ref arg p | |
| smart_pointer.cpp:52:12:52:14 | ref arg call to get | smart_pointer.cpp:52:10:52:10 | ref arg p | TAINT |
| smart_pointer.cpp:56:30:56:50 | call to make_unique | smart_pointer.cpp:57:10:57:10 | p | |
| smart_pointer.cpp:56:52:56:57 | call to source | smart_pointer.cpp:56:30:56:50 | call to make_unique | TAINT |
| smart_pointer.cpp:57:10:57:10 | p | smart_pointer.cpp:57:12:57:14 | call to get | |
| smart_pointer.cpp:57:12:57:14 | ref arg call to get | smart_pointer.cpp:57:10:57:10 | ref arg p | |
| smart_pointer.cpp:57:12:57:14 | ref arg call to get | smart_pointer.cpp:57:10:57:10 | ref arg p | TAINT |
| smart_pointer.cpp:65:28:65:46 | call to make_unique | smart_pointer.cpp:66:10:66:10 | p | |
| smart_pointer.cpp:65:28:65:46 | call to make_unique | smart_pointer.cpp:67:10:67:10 | p | |
| smart_pointer.cpp:65:48:65:53 | call to source | smart_pointer.cpp:65:28:65:46 | call to make_unique | TAINT |
@@ -3319,7 +3319,7 @@
| smart_pointer.cpp:87:3:87:3 | ref arg p | smart_pointer.cpp:89:8:89:8 | p | |
| smart_pointer.cpp:87:3:87:17 | ... = ... | smart_pointer.cpp:87:6:87:6 | x [post update] | |
| smart_pointer.cpp:87:3:87:17 | ... = ... | smart_pointer.cpp:88:11:88:11 | x | |
| smart_pointer.cpp:87:4:87:4 | call to operator-> [post update] | smart_pointer.cpp:87:3:87:3 | ref arg p | |
| smart_pointer.cpp:87:4:87:4 | call to operator-> [post update] | smart_pointer.cpp:87:3:87:3 | ref arg p | TAINT |
| smart_pointer.cpp:87:10:87:15 | call to source | smart_pointer.cpp:87:3:87:17 | ... = ... | |
| smart_pointer.cpp:88:8:88:8 | p | smart_pointer.cpp:88:9:88:9 | call to operator-> | |
| smart_pointer.cpp:88:8:88:8 | ref arg p | smart_pointer.cpp:86:45:86:45 | p | |
@@ -3333,7 +3333,7 @@
| smart_pointer.cpp:91:3:91:3 | ref arg q | smart_pointer.cpp:94:8:94:8 | q | |
| smart_pointer.cpp:91:3:91:20 | ... = ... | smart_pointer.cpp:91:9:91:9 | x [post update] | |
| smart_pointer.cpp:91:3:91:20 | ... = ... | smart_pointer.cpp:92:14:92:14 | x | |
| smart_pointer.cpp:91:4:91:4 | call to operator-> [post update] | smart_pointer.cpp:91:3:91:3 | ref arg q | |
| smart_pointer.cpp:91:4:91:4 | call to operator-> [post update] | smart_pointer.cpp:91:3:91:3 | ref arg q | TAINT |
| smart_pointer.cpp:91:13:91:18 | call to source | smart_pointer.cpp:91:3:91:20 | ... = ... | |
| smart_pointer.cpp:92:8:92:8 | q | smart_pointer.cpp:92:9:92:9 | call to operator-> | |
| smart_pointer.cpp:92:8:92:8 | ref arg q | smart_pointer.cpp:86:67:86:67 | q | |
@@ -3351,21 +3351,21 @@
| smart_pointer.cpp:102:25:102:50 | call to unique_ptr | smart_pointer.cpp:104:8:104:8 | p | |
| smart_pointer.cpp:103:11:103:11 | p | smart_pointer.cpp:103:13:103:15 | call to get | |
| smart_pointer.cpp:103:11:103:11 | ref arg p | smart_pointer.cpp:104:8:104:8 | p | |
| smart_pointer.cpp:103:13:103:15 | ref arg call to get | smart_pointer.cpp:103:11:103:11 | ref arg p | |
| smart_pointer.cpp:103:13:103:15 | ref arg call to get | smart_pointer.cpp:103:11:103:11 | ref arg p | TAINT |
| smart_pointer.cpp:104:8:104:8 | p | smart_pointer.cpp:104:9:104:9 | call to operator-> | |
| smart_pointer.cpp:112:40:112:42 | ptr | smart_pointer.cpp:112:40:112:42 | ptr | |
| smart_pointer.cpp:112:40:112:42 | ptr | smart_pointer.cpp:113:2:113:4 | ptr | |
| smart_pointer.cpp:113:2:113:4 | ptr | smart_pointer.cpp:113:5:113:5 | call to operator-> | |
| smart_pointer.cpp:113:2:113:4 | ref arg ptr | smart_pointer.cpp:112:40:112:42 | ptr | |
| smart_pointer.cpp:113:2:113:18 | ... = ... | smart_pointer.cpp:113:7:113:7 | x [post update] | |
| smart_pointer.cpp:113:5:113:5 | call to operator-> [post update] | smart_pointer.cpp:113:2:113:4 | ref arg ptr | |
| smart_pointer.cpp:113:5:113:5 | call to operator-> [post update] | smart_pointer.cpp:113:2:113:4 | ref arg ptr | TAINT |
| smart_pointer.cpp:113:11:113:16 | call to source | smart_pointer.cpp:113:2:113:18 | ... = ... | |
| smart_pointer.cpp:116:52:116:54 | ptr | smart_pointer.cpp:116:52:116:54 | ptr | |
| smart_pointer.cpp:116:52:116:54 | ptr | smart_pointer.cpp:117:2:117:4 | ptr | |
| smart_pointer.cpp:117:2:117:4 | ptr | smart_pointer.cpp:117:5:117:5 | call to operator-> | |
| smart_pointer.cpp:117:2:117:4 | ref arg ptr | smart_pointer.cpp:116:52:116:54 | ptr | |
| smart_pointer.cpp:117:2:117:18 | ... = ... | smart_pointer.cpp:117:7:117:7 | x [post update] | |
| smart_pointer.cpp:117:5:117:5 | call to operator-> [post update] | smart_pointer.cpp:117:2:117:4 | ref arg ptr | |
| smart_pointer.cpp:117:5:117:5 | call to operator-> [post update] | smart_pointer.cpp:117:2:117:4 | ref arg ptr | TAINT |
| smart_pointer.cpp:117:11:117:16 | call to source | smart_pointer.cpp:117:2:117:18 | ... = ... | |
| smart_pointer.cpp:120:48:120:50 | ptr | smart_pointer.cpp:120:48:120:50 | ptr | |
| smart_pointer.cpp:120:48:120:50 | ptr | smart_pointer.cpp:121:4:121:6 | ptr | |
@@ -3386,12 +3386,12 @@
| smart_pointer.cpp:125:18:125:19 | ref arg p1 | smart_pointer.cpp:124:48:124:49 | p1 | |
| smart_pointer.cpp:125:18:125:19 | ref arg p1 | smart_pointer.cpp:126:8:126:9 | p1 | |
| smart_pointer.cpp:125:18:125:22 | ref arg call to shared_ptr | smart_pointer.cpp:125:22:125:22 | q [inner post update] | |
| smart_pointer.cpp:125:20:125:20 | call to operator-> [post update] | smart_pointer.cpp:125:18:125:19 | ref arg p1 | |
| smart_pointer.cpp:125:20:125:20 | call to operator-> [post update] | smart_pointer.cpp:125:18:125:19 | ref arg p1 | TAINT |
| smart_pointer.cpp:125:22:125:22 | q | smart_pointer.cpp:125:18:125:22 | call to shared_ptr | |
| smart_pointer.cpp:125:22:125:22 | ref arg q | smart_pointer.cpp:125:22:125:22 | q [inner post update] | |
| smart_pointer.cpp:126:8:126:9 | p1 | smart_pointer.cpp:126:10:126:10 | call to operator-> | |
| smart_pointer.cpp:126:8:126:9 | ref arg p1 | smart_pointer.cpp:124:48:124:49 | p1 | |
| smart_pointer.cpp:126:10:126:10 | call to operator-> [post update] | smart_pointer.cpp:126:8:126:9 | ref arg p1 | |
| smart_pointer.cpp:126:10:126:10 | call to operator-> [post update] | smart_pointer.cpp:126:8:126:9 | ref arg p1 | TAINT |
| smart_pointer.cpp:126:12:126:12 | q | smart_pointer.cpp:126:13:126:13 | call to operator-> | |
| smart_pointer.cpp:128:13:128:13 | call to operator* | smart_pointer.cpp:128:13:128:15 | call to shared_ptr | TAINT |
| smart_pointer.cpp:128:13:128:13 | ref arg call to operator* | smart_pointer.cpp:124:90:124:91 | p2 | |
@@ -3422,10 +3422,10 @@
| smart_pointer.cpp:133:23:133:24 | p1 | smart_pointer.cpp:133:25:133:25 | call to operator-> | |
| smart_pointer.cpp:133:23:133:24 | ref arg p1 | smart_pointer.cpp:132:53:132:54 | p1 | |
| smart_pointer.cpp:133:23:133:24 | ref arg p1 | smart_pointer.cpp:134:8:134:9 | p1 | |
| smart_pointer.cpp:133:25:133:25 | call to operator-> [post update] | smart_pointer.cpp:133:23:133:24 | ref arg p1 | |
| smart_pointer.cpp:133:25:133:25 | call to operator-> [post update] | smart_pointer.cpp:133:23:133:24 | ref arg p1 | TAINT |
| smart_pointer.cpp:134:8:134:9 | p1 | smart_pointer.cpp:134:10:134:10 | call to operator-> | |
| smart_pointer.cpp:134:8:134:9 | ref arg p1 | smart_pointer.cpp:132:53:132:54 | p1 | |
| smart_pointer.cpp:134:10:134:10 | call to operator-> [post update] | smart_pointer.cpp:134:8:134:9 | ref arg p1 | |
| smart_pointer.cpp:134:10:134:10 | call to operator-> [post update] | smart_pointer.cpp:134:8:134:9 | ref arg p1 | TAINT |
| smart_pointer.cpp:134:12:134:12 | q | smart_pointer.cpp:134:13:134:13 | call to operator-> | |
| smart_pointer.cpp:136:17:136:17 | ref arg call to operator* | smart_pointer.cpp:132:95:132:96 | p2 | |
| smart_pointer.cpp:136:17:136:17 | ref arg call to operator* | smart_pointer.cpp:136:18:136:19 | p2 [inner post update] | |

View File

@@ -189,3 +189,30 @@ int *&conversionInFlow() {
int *&pRef = p; // has conversion in the middle of data flow
return pRef; // BAD [NOT DETECTED]
}
namespace std {
template<typename T>
class shared_ptr {
public:
shared_ptr() noexcept;
explicit shared_ptr(T*);
shared_ptr(const shared_ptr&) noexcept;
template<class U> shared_ptr(const shared_ptr<U>&) noexcept;
template<class U> shared_ptr(shared_ptr<U>&&) noexcept;
shared_ptr<T>& operator=(const shared_ptr<T>&) noexcept;
shared_ptr<T>& operator=(shared_ptr<T>&&) noexcept;
T& operator*() const noexcept;
T* operator->() const noexcept;
T* get() const noexcept;
};
}
auto make_read_port()
{
auto port = std::shared_ptr<int>(new int);
auto ptr = port.get();
return ptr; // GOOD
}

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* `System.Console.Read` methods have been added as data flow sources of local user input.

View File

@@ -193,6 +193,16 @@ namespace Semmle.Extraction.CSharp.Entities
return Default.CreateGenerated(cx, parent, childIndex, location, parameter.Type.IsReferenceType ? ValueAsString(null) : null);
}
if (parameter.Type.SpecialType == SpecialType.System_Object)
{
// this can happen in VB.NET
cx.ExtractionError($"Extracting default argument value 'object {parameter.Name} = default' instead of 'object {parameter.Name} = {defaultValue}'. The latter is not supported in C#.",
null, null, severity: Util.Logging.Severity.Warning);
// we're generating a default expression:
return Default.CreateGenerated(cx, parent, childIndex, location, ValueAsString(null));
}
// const literal:
return Literal.CreateGenerated(cx, parent, childIndex, parameter.Type, defaultValue, location);
}

View File

@@ -18,36 +18,6 @@ import csharp
import Dispose
import semmle.code.csharp.frameworks.System
/**
* Gets an exception type that may be thrown during the execution of method `m`.
* Assumes any exception may be thrown by library types.
*/
Class getAThrownException(Method m) {
m.fromLibrary() and
result = any(SystemExceptionClass sc)
or
exists(ControlFlowElement cfe |
cfe = any(ThrowElement te | result = te.getExpr().getType()) or
cfe = any(MethodCall mc | result = getAThrownException(mc.getARuntimeTarget()))
|
cfe.getEnclosingCallable() = m and
not isTriedAgainstException(cfe, result)
)
}
/**
* Holds if control flow element is tried against throwing an exception of type
* `ec`.
*/
pragma[noinline]
predicate isTriedAgainstException(ControlFlowElement cfe, ExceptionClass ec) {
(cfe instanceof ThrowElement or cfe instanceof MethodCall) and
exists(TryStmt ts |
ts.getATriedElement() = cfe and
exists(ts.getAnExceptionHandler(ec))
)
}
private class DisposeCall extends MethodCall {
DisposeCall() { this.getTarget() instanceof DisposeMethod }
}
@@ -78,8 +48,17 @@ predicate disposeReachableFromDisposableCreation(DisposeCall disposeCall, Expr d
reachesDisposeCall(disposeCall, DataFlow::exprNode(disposableCreation))
}
class MethodCallThatMayThrow extends MethodCall {
MethodCallThatMayThrow() { exists(getAThrownException(this.getARuntimeTarget())) }
/**
* Holds if control flow element is tried against throwing an exception of type
* `ec`.
*/
pragma[noinline]
predicate isTriedAgainstException(ControlFlowElement cfe, ExceptionClass ec) {
(cfe instanceof ThrowElement or cfe instanceof MethodCall) and
exists(TryStmt ts |
ts.getATriedElement() = cfe and
exists(ts.getAnExceptionHandler(ec))
)
}
ControlFlowElement getACatchOrFinallyClauseChild() {
@@ -88,15 +67,71 @@ ControlFlowElement getACatchOrFinallyClauseChild() {
result = getACatchOrFinallyClauseChild().getAChild()
}
from DisposeCall disposeCall, Expr disposableCreation, MethodCallThatMayThrow callThatThrows
where
private predicate candidate(DisposeCall disposeCall, Call call, Expr disposableCreation) {
disposeReachableFromDisposableCreation(disposeCall, disposableCreation) and
// The dispose call is not, itself, within a dispose method.
not disposeCall.getEnclosingCallable() instanceof DisposeMethod and
// Dispose call not within a finally or catch block
not getACatchOrFinallyClauseChild() = disposeCall and
// At least one method call exists between the allocation and disposal that could throw
disposableCreation.getAReachableElement() = callThatThrows and
callThatThrows.getAReachableElement() = disposeCall
disposableCreation.getAReachableElement() = call and
call.getAReachableElement() = disposeCall
}
private class RelevantMethod extends Method {
RelevantMethod() {
exists(Call call |
candidate(_, call, _) and
this = call.getARuntimeTarget()
)
or
exists(RelevantMethod other | other.calls(this))
}
pragma[noinline]
private RelevantMethod callsNoTry() {
exists(MethodCall mc |
result = mc.getARuntimeTarget() and
not isTriedAgainstException(mc, _) and
mc.getEnclosingCallable() = this
)
}
pragma[noinline]
private RelevantMethod callsInTry(MethodCall mc) {
result = mc.getARuntimeTarget() and
isTriedAgainstException(mc, _) and
mc.getEnclosingCallable() = this
}
/**
* Gets an exception type that may be thrown during the execution of this method.
* Assumes any exception may be thrown by library types.
*/
Class getAThrownException() {
this.fromLibrary() and
result instanceof SystemExceptionClass
or
exists(ControlFlowElement cfe |
result = cfe.(ThrowElement).getExpr().getType() and
cfe.getEnclosingCallable() = this
or
result = this.callsInTry(cfe).getAThrownException()
|
not isTriedAgainstException(cfe, result)
)
or
result = this.callsNoTry().getAThrownException()
}
}
class MethodCallThatMayThrow extends MethodCall {
MethodCallThatMayThrow() {
exists(this.getARuntimeTarget().(RelevantMethod).getAThrownException())
}
}
from DisposeCall disposeCall, Expr disposableCreation, MethodCallThatMayThrow callThatThrows
where candidate(disposeCall, callThatThrows, disposableCreation)
select disposeCall, "Dispose missed if exception is thrown by $@.", callThatThrows,
callThatThrows.toString()

View File

@@ -0,0 +1,11 @@
/**
* @id cs/summary/lines-of-code
* @name Total lines of code in the database
* @description The total number of lines of code across all files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
*/
import csharp
select sum(File f | f.fromSource() | f.getNumberOfLinesOfCode())

View File

@@ -57,7 +57,8 @@ private Element getRealParent(Expr expr) { result = expr.getParent() }
*/
predicate isIRConstant(Expr expr) { exists(expr.getValue()) }
// Pulled out to work around QL-796
// Pulled out for performance. See
// https://github.com/github/codeql-coreql-team/issues/1044.
private predicate isOrphan(Expr expr) { not exists(getRealParent(expr)) }
/**

View File

@@ -316,6 +316,15 @@ private module SsaDefReaches {
)
}
/**
* Holds if the reference to `def` at index `i` in basic block `bb` is the
* last reference to `v` inside `bb`.
*/
pragma[noinline]
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
exists(ssaDefRank(def, v, bb, _, _))
}
@@ -351,8 +360,7 @@ private module SsaDefReaches {
*/
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and
variableRead(bb2, i2, _, _)
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
}
}
@@ -434,15 +442,22 @@ predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2
bb2 = bb1
)
or
exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and
lastSsaRef(def, _, bb1, i1) and
defAdjacentRead(def, bb1, bb2, i2)
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
exists(SourceVariable v | v = def.getSourceVariable() |
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
ssaRef(bb1, i1, v, SsaDef())
or
variableRead(bb1, i1, v, true)
@@ -475,17 +490,19 @@ predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, Ba
*/
pragma[nomagic]
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) |
exists(SourceVariable v |
// Next reference to `v` inside `bb` is a write
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
exists(int rnk, int j |
rnk = ssaDefRank(def, v, bb, i, _) and
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
)
or
// Can reach a write using one or more steps
rnk = maxSsaRefRank(bb, v) and
lastSsaRef(def, v, bb, i) and
exists(BasicBlock bb2 |
varBlockReaches(def, bb, bb2) and
next.definesAt(v, bb2, j) and
1 = ssaRefRank(bb2, j, v, SsaDef())
1 = ssaDefRank(next, v, bb2, _, SsaDef())
)
)
}
@@ -539,7 +556,8 @@ pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
lastRefRedef(def, bb, i, _)
or
exists(SourceVariable v | ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) |
lastSsaRef(def, _, bb, i) and
(
// Can reach exit directly
bb instanceof ExitBasicBlock
or

View File

@@ -49,6 +49,7 @@ module Stages {
cached
module DataFlowStage {
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
@@ -78,6 +79,8 @@ module Stages {
or
exists(CallContext cc)
or
exists(any(DataFlowCall c).getEnclosingCallable())
or
forceCachingInSameStageRev()
}
}

View File

@@ -192,7 +192,7 @@ class File extends Container, @file {
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
/** Holds if this file contains source code. */
predicate fromSource() { this.getNumberOfLinesOfCode() > 0 }
predicate fromSource() { files(this, _, _, "cs", _) }
/** Holds if this file is a library. */
predicate fromLibrary() {

View File

@@ -316,6 +316,15 @@ private module SsaDefReaches {
)
}
/**
* Holds if the reference to `def` at index `i` in basic block `bb` is the
* last reference to `v` inside `bb`.
*/
pragma[noinline]
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
exists(ssaDefRank(def, v, bb, _, _))
}
@@ -351,8 +360,7 @@ private module SsaDefReaches {
*/
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and
variableRead(bb2, i2, _, _)
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
}
}
@@ -434,15 +442,22 @@ predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2
bb2 = bb1
)
or
exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and
lastSsaRef(def, _, bb1, i1) and
defAdjacentRead(def, bb1, bb2, i2)
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
exists(SourceVariable v | v = def.getSourceVariable() |
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
ssaRef(bb1, i1, v, SsaDef())
or
variableRead(bb1, i1, v, true)
@@ -475,17 +490,19 @@ predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, Ba
*/
pragma[nomagic]
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) |
exists(SourceVariable v |
// Next reference to `v` inside `bb` is a write
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
exists(int rnk, int j |
rnk = ssaDefRank(def, v, bb, i, _) and
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
)
or
// Can reach a write using one or more steps
rnk = maxSsaRefRank(bb, v) and
lastSsaRef(def, v, bb, i) and
exists(BasicBlock bb2 |
varBlockReaches(def, bb, bb2) and
next.definesAt(v, bb2, j) and
1 = ssaRefRank(bb2, j, v, SsaDef())
1 = ssaDefRank(next, v, bb2, _, SsaDef())
)
)
}
@@ -539,7 +556,8 @@ pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
lastRefRedef(def, bb, i, _)
or
exists(SourceVariable v | ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) |
lastSsaRef(def, _, bb, i) and
(
// Can reach exit directly
bb instanceof ExitBasicBlock
or

View File

@@ -4,6 +4,7 @@ private import dotnet
private import DataFlowPublic
private import DataFlowPrivate
private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.Caching
private import semmle.code.csharp.dataflow.FlowSummary
private import semmle.code.csharp.dispatch.Dispatch
private import semmle.code.csharp.frameworks.system.Collections
@@ -69,8 +70,6 @@ private predicate transitiveCapturedCallTarget(ControlFlow::Nodes::ElementNode c
cached
private module Cached {
private import semmle.code.csharp.Caching
cached
newtype TReturnKind =
TNormalReturnKind() { Stages::DataFlowStage::forceCachingInSameStage() } or
@@ -247,6 +246,7 @@ abstract class DataFlowCall extends TDataFlowCall {
abstract DataFlow::Node getNode();
/** Gets the enclosing callable of this call. */
cached
abstract DataFlowCallable getEnclosingCallable();
/** Gets the underlying expression, if any. */
@@ -280,7 +280,10 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallable() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = cfn.getEnclosingCallable()
}
override string toString() { result = cfn.toString() }

View File

@@ -21,9 +21,11 @@ private import semmle.code.csharp.frameworks.system.threading.Tasks
abstract class NodeImpl extends Node {
/** Do not call: use `getEnclosingCallable()` instead. */
cached
abstract DataFlowCallable getEnclosingCallableImpl();
/** Do not call: use `getType()` instead. */
cached
abstract DotNet::Type getTypeImpl();
/** Gets the type of this node used for type pruning. */
@@ -39,27 +41,39 @@ abstract class NodeImpl extends Node {
}
/** Do not call: use `getControlFlowNode()` instead. */
cached
abstract ControlFlow::Node getControlFlowNodeImpl();
/** Do not call: use `getLocation()` instead. */
cached
abstract Location getLocationImpl();
/** Do not call: use `toString()` instead. */
cached
abstract string toStringImpl();
}
private class ExprNodeImpl extends ExprNode, NodeImpl {
override DataFlowCallable getEnclosingCallableImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.getExpr().getEnclosingCallable()
}
override DotNet::Type getTypeImpl() { result = this.getExpr().getType() }
override DotNet::Type getTypeImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.getExpr().getType()
}
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { this = TExprNode(result) }
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and this = TExprNode(result)
}
override Location getLocationImpl() { result = this.getExpr().getLocation() }
override Location getLocationImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getLocation()
}
override string toStringImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.getControlFlowNode().toString()
or
exists(CIL::Expr e |
@@ -967,6 +981,16 @@ private module Cached {
or
n.asExpr() = any(WithExpr we).getInitializer()
}
cached
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNodeImpl).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNodeImpl).argumentOf(call, pos)
}
}
import Cached
@@ -992,8 +1016,6 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
}
abstract class ParameterNodeImpl extends NodeImpl {
abstract DotNet::Parameter getParameter();
abstract predicate isParameterOf(DataFlowCallable c, int i);
}
@@ -1010,11 +1032,9 @@ private module ParameterNodes {
/** Gets the SSA definition corresponding to this parameter, if any. */
Ssa::ExplicitDefinition getSsaDefinition() {
result.getADefinition().(AssignableDefinitions::ImplicitParameterDefinition).getParameter() =
this.getParameter()
parameter
}
override DotNet::Parameter getParameter() { result = parameter }
override predicate isParameterOf(DataFlowCallable c, int i) { c.getParameter(i) = parameter }
override DataFlowCallable getEnclosingCallableImpl() { result = parameter.getCallable() }
@@ -1037,8 +1057,6 @@ private module ParameterNodes {
/** Gets the callable containing this implicit instance parameter. */
Callable getCallable() { result = callable }
override DotNet::Parameter getParameter() { none() }
override predicate isParameterOf(DataFlowCallable c, int pos) { callable = c and pos = -1 }
override DataFlowCallable getEnclosingCallableImpl() { result = callable }
@@ -1113,8 +1131,6 @@ private module ParameterNodes {
/** Gets the captured variable that this implicit parameter models. */
LocalScopeVariable getVariable() { result = def.getVariable() }
override DotNet::Parameter getParameter() { none() }
override predicate isParameterOf(DataFlowCallable c, int i) {
i = getParameterPosition(def) and
c = this.getEnclosingCallable()
@@ -1125,13 +1141,15 @@ private module ParameterNodes {
import ParameterNodes
/** A data-flow node that represents a call argument. */
abstract class ArgumentNode extends Node {
/** Holds if this argument occurs at the given position in the given call. */
cached
abstract predicate argumentOf(DataFlowCall call, int pos);
class ArgumentNode extends Node {
ArgumentNode() { argumentNode(this, _, _) }
/** Gets the call in which this node is an argument. */
final DataFlowCall getCall() { this.argumentOf(result, _) }
/** Holds if this argument occurs at the given position in the given call. */
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
}
abstract private class ArgumentNodeImpl extends Node {
abstract predicate argumentOf(DataFlowCall call, int pos);
}
private module ArgumentNodes {
@@ -1149,7 +1167,7 @@ private module ArgumentNodes {
}
/** A data-flow node that represents an explicit call argument. */
class ExplicitArgumentNode extends ArgumentNode {
class ExplicitArgumentNode extends ArgumentNodeImpl {
ExplicitArgumentNode() {
this.asExpr() instanceof Argument
or
@@ -1157,7 +1175,6 @@ private module ArgumentNodes {
}
override predicate argumentOf(DataFlowCall call, int pos) {
Stages::DataFlowStage::forceCachingInSameStage() and
exists(ArgumentConfiguration x, Expr c, Argument arg |
arg = this.asExpr() and
c = call.getExpr() and
@@ -1189,7 +1206,8 @@ private module ArgumentNodes {
* } }
* ```
*/
class ImplicitCapturedArgumentNode extends ArgumentNode, NodeImpl, TImplicitCapturedArgumentNode {
class ImplicitCapturedArgumentNode extends ArgumentNodeImpl, NodeImpl,
TImplicitCapturedArgumentNode {
private LocalScopeVariable v;
private ControlFlow::Nodes::ElementNode cfn;
@@ -1231,7 +1249,7 @@ private module ArgumentNodes {
* A node that corresponds to the value of an object creation (`new C()`) before
* the constructor has run.
*/
class MallocNode extends ArgumentNode, NodeImpl, TMallocNode {
class MallocNode extends ArgumentNodeImpl, NodeImpl, TMallocNode {
private ControlFlow::Nodes::ElementNode cfn;
MallocNode() { this = TMallocNode(cfn) }
@@ -1266,7 +1284,7 @@ private module ArgumentNodes {
* and that argument is itself a compatible array, for example
* `Foo(new[] { "a", "b", "c" })`.
*/
class ParamsArgumentNode extends ArgumentNode, NodeImpl, TParamsArgumentNode {
class ParamsArgumentNode extends ArgumentNodeImpl, NodeImpl, TParamsArgumentNode {
private ControlFlow::Node callCfn;
ParamsArgumentNode() { this = TParamsArgumentNode(callCfn) }
@@ -1291,7 +1309,7 @@ private module ArgumentNodes {
override string toStringImpl() { result = "[implicit array creation] " + callCfn }
}
private class SummaryArgumentNode extends SummaryNode, ArgumentNode {
private class SummaryArgumentNode extends SummaryNode, ArgumentNodeImpl {
private DataFlowCall c;
private int i;
@@ -1324,10 +1342,7 @@ private module ReturnNodes {
)
}
override NormalReturnKind getKind() {
any(DotNet::Callable c).canReturn(this.getExpr()) and
exists(result)
}
override NormalReturnKind getKind() { exists(result) }
}
/**
@@ -1744,7 +1759,10 @@ class DataFlowType extends Gvn::GvnType {
}
/** Gets the type of `n` used for type pruning. */
DataFlowType getNodeType(NodeImpl n) { result = n.getDataFlowType() }
pragma[inline]
Gvn::GvnType getNodeType(NodeImpl n) {
pragma[only_bind_into](result) = pragma[only_bind_out](n).getDataFlowType()
}
/** Gets a string representation of a `DataFlowType`. */
string ppReprType(DataFlowType t) { result = t.toString() }
@@ -1819,7 +1837,8 @@ private module PostUpdateNodes {
* Such a node acts as both a post-update node for the `MallocNode`, as well as
* a pre-update node for the `ObjectCreationNode`.
*/
class ObjectInitializerNode extends PostUpdateNode, NodeImpl, ArgumentNode, TObjectInitializerNode {
class ObjectInitializerNode extends PostUpdateNode, NodeImpl, ArgumentNodeImpl,
TObjectInitializerNode {
private ObjectCreation oc;
private ControlFlow::Nodes::ElementNode cfn;

View File

@@ -3,7 +3,6 @@ private import cil
private import dotnet
private import DataFlowDispatch
private import DataFlowPrivate
private import semmle.code.csharp.Caching
private import semmle.code.csharp.controlflow.Guards
private import semmle.code.csharp.Unification
@@ -38,38 +37,21 @@ class Node extends TNode {
}
/** Gets the type of this node. */
cached
final DotNet::Type getType() {
Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl()
}
final DotNet::Type getType() { result = this.(NodeImpl).getTypeImpl() }
/** Gets the enclosing callable of this node. */
cached
final DataFlowCallable getEnclosingCallable() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.(NodeImpl).getEnclosingCallableImpl()
}
/** Gets the control flow node corresponding to this node, if any. */
cached
final ControlFlow::Node getControlFlowNode() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.(NodeImpl).getControlFlowNodeImpl()
}
final ControlFlow::Node getControlFlowNode() { result = this.(NodeImpl).getControlFlowNodeImpl() }
/** Gets a textual representation of this node. */
cached
final string toString() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.(NodeImpl).toStringImpl()
}
final string toString() { result = this.(NodeImpl).toStringImpl() }
/** Gets the location of this node. */
cached
final Location getLocation() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.(NodeImpl).getLocationImpl()
}
final Location getLocation() { result = this.(NodeImpl).getLocationImpl() }
/**
* Holds if this element is at the specified location.
@@ -81,7 +63,7 @@ class Node extends TNode {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -117,18 +99,18 @@ class ExprNode extends Node {
* flow graph.
*/
class ParameterNode extends Node {
private ParameterNodeImpl p;
ParameterNode() { this = p }
ParameterNode() { parameterNode(this, _, _) }
/** Gets the parameter corresponding to this node, if any. */
DotNet::Parameter getParameter() { result = p.getParameter() }
DotNet::Parameter getParameter() {
exists(DataFlowCallable c, int i | this.isParameterOf(c, i) and result = c.getParameter(i))
}
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { p.isParameterOf(c, i) }
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
}
/** A definition, viewed as a node in a data flow graph. */
@@ -166,6 +148,7 @@ predicate localFlowStep = localFlowStepImpl/2;
* Holds if data flows from `source` to `sink` in zero or more local
* (intra-procedural) steps.
*/
pragma[inline]
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
/**

View File

@@ -446,7 +446,19 @@ module Private {
summary(c, inputContents, outputContents, preservesValue) and
pred = summaryNodeInputState(c, inputContents) and
succ = summaryNodeOutputState(c, outputContents)
|
preservesValue = true
or
preservesValue = false and not summary(c, inputContents, outputContents, true)
)
or
// If flow through a method updates a parameter from some input A, and that
// parameter also is returned through B, then we'd like a combined flow from A
// to B as well. As an example, this simplifies modeling of fluent methods:
// for `StringBuilder.append(x)` with a specified value flow from qualifier to
// return value and taint flow from argument 0 to the qualifier, then this
// allows us to infer taint flow from argument 0 to the return value.
summaryPostUpdateNode(pred, succ) and preservesValue = true
}
/**

View File

@@ -268,56 +268,146 @@ private module CallGraph {
)
}
/**
* A simple flow step that does not take flow through fields or flow out
* of callables into account.
*/
pragma[nomagic]
private predicate delegateFlowStep(Expr pred, Expr succ) {
Steps::stepClosed(pred, succ)
or
exists(Call call, Callable callable |
callable.getUnboundDeclaration().canReturn(pred) and
call = succ
|
callable = call.getTarget() or
callable = call.getTarget().(Method).getAnOverrider+() or
callable = call.getTarget().(Method).getAnUltimateImplementor() or
callable = getARuntimeDelegateTarget(call, false)
)
or
pred = succ.(DelegateCreation).getArgument()
or
exists(AssignableDefinition def, Assignable a |
a instanceof Field or
a instanceof Property
|
a = def.getTarget() and
succ.(AssignableRead) = a.getAnAccess() and
pred = def.getSource()
)
or
exists(AddEventExpr ae | succ.(EventAccess).getTarget() = ae.getTarget() |
pred = ae.getRValue()
)
}
private predicate reachesDelegateCall(Expr e) {
delegateCall(_, e, _)
private predicate delegateCreationReaches(Callable c, Expr e) {
delegateCreation(e, c, _)
or
exists(Expr mid | reachesDelegateCall(mid) | delegateFlowStep(e, mid))
exists(Expr mid |
delegateCreationReaches(c, mid) and
delegateFlowStep(mid, e)
)
}
pragma[nomagic]
private predicate delegateFlowStepReaches(Expr pred, Expr succ) {
delegateFlowStep(pred, succ) and
reachesDelegateCall(succ)
private predicate reachesDelegateCall(Expr e, Call c, boolean libraryDelegateCall) {
delegateCall(c, e, libraryDelegateCall)
or
exists(Expr mid |
reachesDelegateCall(mid, c, libraryDelegateCall) and
delegateFlowStep(e, mid)
)
}
private Expr delegateCallSource(Callable c) {
delegateCreation(result, c, _)
or
delegateFlowStepReaches(delegateCallSource(c), result)
/**
* A "busy" flow element, that is, a node in the data-flow graph that typically
* has a large fan-in or a large fan-out (or both).
*
* For such busy elements, we do not track flow directly from all delegate
* creations, but instead we first perform a flow analysis between busy elements,
* and then only in the end join up with delegate creations and delegate calls.
*/
abstract private class BusyFlowElement extends Element {
pragma[nomagic]
abstract Expr getAnInput();
pragma[nomagic]
abstract Expr getAnOutput();
/** Holds if this element can be reached from expression `e`. */
pragma[nomagic]
private predicate exprReaches(Expr e) {
this.reachesCall(_) and
e = this.getAnInput()
or
exists(Expr mid |
this.exprReaches(mid) and
delegateFlowStep(e, mid)
)
}
/**
* Holds if this element can reach a delegate call `c` directly without
* passing through another busy element.
*/
pragma[nomagic]
predicate delegateCall(Call c, boolean libraryDelegateCall) {
reachesDelegateCall(this.getAnOutput(), c, libraryDelegateCall)
}
pragma[nomagic]
private BusyFlowElement getASuccessor() { result.exprReaches(this.getAnOutput()) }
/**
* Holds if this element reaches another busy element `other`,
* which can reach a delegate call directly without passing
* through another busy element.
*/
pragma[nomagic]
private predicate reachesCall(BusyFlowElement other) {
this = other and
other.delegateCall(_, _)
or
this.getASuccessor().reachesCall(other)
}
/** Holds if this element is reached by a delegate creation for `c`. */
pragma[nomagic]
predicate isReachedBy(Callable c) {
exists(BusyFlowElement pred |
pred.reachesCall(this) and
delegateCreationReaches(c, pred.getAnInput())
)
}
}
private class TFieldOrProperty = @field or @property;
private class FieldOrPropertyFlow extends BusyFlowElement, Assignable, TFieldOrProperty {
final override Expr getAnInput() {
exists(Assignable target |
target = this.getUnboundDeclaration() and
result = target.getAnAssignedValue()
)
}
final override AssignableRead getAnOutput() {
exists(Assignable target |
target = this.getUnboundDeclaration() and
result = target.getAnAccess()
)
}
}
private class CallOutputFlow extends BusyFlowElement, Callable {
final override Expr getAnInput() { this.canReturn(result) }
final override Call getAnOutput() {
exists(Callable target | this = target.getUnboundDeclaration() |
target = result.getTarget() or
target = result.getTarget().(Method).getAnOverrider+() or
target = result.getTarget().(Method).getAnUltimateImplementor() or
target = getARuntimeDelegateTarget(result, false)
)
}
}
/** Gets a run-time target for the delegate call `c`. */
pragma[nomagic]
Callable getARuntimeDelegateTarget(Call c, boolean libraryDelegateCall) {
delegateCall(c, delegateCallSource(result), libraryDelegateCall)
// directly resolvable without going through a "busy" element
exists(Expr e |
delegateCreationReaches(result, e) and
delegateCall(c, e, libraryDelegateCall)
)
or
// resolvable by going through one or more "busy" elements
exists(BusyFlowElement busy |
busy.isReachedBy(result) and
busy.delegateCall(c, libraryDelegateCall)
)
}
}

View File

@@ -316,6 +316,15 @@ private module SsaDefReaches {
)
}
/**
* Holds if the reference to `def` at index `i` in basic block `bb` is the
* last reference to `v` inside `bb`.
*/
pragma[noinline]
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
exists(ssaDefRank(def, v, bb, _, _))
}
@@ -351,8 +360,7 @@ private module SsaDefReaches {
*/
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and
variableRead(bb2, i2, _, _)
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
}
}
@@ -434,15 +442,22 @@ predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2
bb2 = bb1
)
or
exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and
lastSsaRef(def, _, bb1, i1) and
defAdjacentRead(def, bb1, bb2, i2)
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
exists(SourceVariable v | v = def.getSourceVariable() |
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
ssaRef(bb1, i1, v, SsaDef())
or
variableRead(bb1, i1, v, true)
@@ -475,17 +490,19 @@ predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, Ba
*/
pragma[nomagic]
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) |
exists(SourceVariable v |
// Next reference to `v` inside `bb` is a write
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
exists(int rnk, int j |
rnk = ssaDefRank(def, v, bb, i, _) and
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
)
or
// Can reach a write using one or more steps
rnk = maxSsaRefRank(bb, v) and
lastSsaRef(def, v, bb, i) and
exists(BasicBlock bb2 |
varBlockReaches(def, bb, bb2) and
next.definesAt(v, bb2, j) and
1 = ssaRefRank(bb2, j, v, SsaDef())
1 = ssaDefRank(next, v, bb2, _, SsaDef())
)
)
}
@@ -539,7 +556,8 @@ pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
lastRefRedef(def, bb, i, _)
or
exists(SourceVariable v | ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) |
lastSsaRef(def, _, bb, i) and
(
// Can reach exit directly
bb instanceof ExitBasicBlock
or

View File

@@ -316,6 +316,15 @@ private module SsaDefReaches {
)
}
/**
* Holds if the reference to `def` at index `i` in basic block `bb` is the
* last reference to `v` inside `bb`.
*/
pragma[noinline]
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
exists(ssaDefRank(def, v, bb, _, _))
}
@@ -351,8 +360,7 @@ private module SsaDefReaches {
*/
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and
variableRead(bb2, i2, _, _)
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
}
}
@@ -434,15 +442,22 @@ predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2
bb2 = bb1
)
or
exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and
lastSsaRef(def, _, bb1, i1) and
defAdjacentRead(def, bb1, bb2, i2)
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
exists(SourceVariable v | v = def.getSourceVariable() |
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
ssaRef(bb1, i1, v, SsaDef())
or
variableRead(bb1, i1, v, true)
@@ -475,17 +490,19 @@ predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, Ba
*/
pragma[nomagic]
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) |
exists(SourceVariable v |
// Next reference to `v` inside `bb` is a write
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
exists(int rnk, int j |
rnk = ssaDefRank(def, v, bb, i, _) and
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
)
or
// Can reach a write using one or more steps
rnk = maxSsaRefRank(bb, v) and
lastSsaRef(def, v, bb, i) and
exists(BasicBlock bb2 |
varBlockReaches(def, bb, bb2) and
next.definesAt(v, bb2, j) and
1 = ssaRefRank(bb2, j, v, SsaDef())
1 = ssaDefRank(next, v, bb2, _, SsaDef())
)
)
}
@@ -539,7 +556,8 @@ pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
lastRefRedef(def, bb, i, _)
or
exists(SourceVariable v | ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) |
lastSsaRef(def, _, bb, i) and
(
// Can reach exit directly
bb instanceof ExitBasicBlock
or

View File

@@ -233,71 +233,61 @@ private module Internal {
}
pragma[noinline]
private predicate hasOverrider(OverridableCallable oc, ValueOrRefType t) {
exists(oc.getAnOverrider(t))
private predicate hasOverrider(OverridableCallable oc, Gvn::GvnType t) {
exists(oc.getAnOverrider(any(ValueOrRefType t0 | Gvn::getGlobalValueNumber(t0) = t)))
}
pragma[noinline]
private predicate hasCallable(OverridableCallable source, ValueOrRefType t, OverridableCallable c) {
private predicate hasCallable(OverridableCallable source, Gvn::GvnType t, OverridableCallable c) {
c.getUnboundDeclaration() = source and
t.hasCallable(c) and
any(ValueOrRefType t0 | Gvn::getGlobalValueNumber(t0) = t).hasCallable(c) and
hasOverrider(c, t) and
hasQualifierTypeOverridden0(t, _) and
hasQualifierTypeOverridden1(source, _)
}
pragma[noinline]
private Unification::ConstrainedTypeParameter getAConstrainedTypeParameterQualifierType(
DispatchMethodOrAccessorCall call
) {
result = getAPossibleType(call.getQualifier(), false)
}
pragma[noinline]
private predicate constrainedTypeParameterQualifierTypeSubsumes(
ValueOrRefType t, Unification::ConstrainedTypeParameter tp
) {
tp = getAConstrainedTypeParameterQualifierType(_) and
tp.subsumes(t)
}
pragma[noinline]
private predicate hasQualifierTypeOverridden0(ValueOrRefType t, DispatchMethodOrAccessorCall call) {
hasOverrider(_, t) and
(
exists(Type t0, Type t1 |
t0 = getAPossibleType(call.getQualifier(), false) and
t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()]
|
t = t1
or
Unification::subsumes(t1, t)
)
or
constrainedTypeParameterQualifierTypeSubsumes(t,
getAConstrainedTypeParameterQualifierType(call))
)
}
pragma[noinline]
private predicate hasQualifierTypeOverridden1(
OverridableCallable c, DispatchMethodOrAccessorCall call
) {
exists(OverridableCallable target | call.getAStaticTarget() = target |
c = target.getUnboundDeclaration()
or
c = target.getAnUltimateImplementor().getUnboundDeclaration()
)
source = any(DispatchMethodOrAccessorCall call).getAStaticTargetExt()
}
abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl {
pragma[noinline]
OverridableCallable getAStaticTargetExt() {
exists(OverridableCallable target | this.getAStaticTarget() = target |
result = target.getUnboundDeclaration()
or
result = target.getAnUltimateImplementor().getUnboundDeclaration()
)
}
pragma[nomagic]
predicate hasQualifierTypeInherited(Type t) { t = getAPossibleType(this.getQualifier(), _) }
pragma[noinline]
private predicate hasSubsumedQualifierType(Gvn::GvnType t) {
hasOverrider(_, t) and
exists(Type t0 |
t0 = getAPossibleType(this.getQualifier(), false) and
not t0 instanceof TypeParameter
|
t = Gvn::getGlobalValueNumber(t0)
or
Gvn::subsumes(Gvn::getGlobalValueNumber(t0), t)
)
}
pragma[noinline]
private predicate hasConstrainedTypeParameterQualifierType(
Unification::ConstrainedTypeParameter tp
) {
tp = getAPossibleType(this.getQualifier(), false)
}
pragma[noinline]
private predicate hasUnconstrainedTypeParameterQualifierType() {
getAPossibleType(this.getQualifier(), false) instanceof
Unification::UnconstrainedTypeParameter
}
pragma[nomagic]
predicate hasQualifierTypeOverridden(ValueOrRefType t, OverridableCallable c) {
hasQualifierTypeOverridden0(t, this) and
hasCallable(any(OverridableCallable oc | hasQualifierTypeOverridden1(oc, this)), t, c)
predicate hasSubsumedQualifierTypeOverridden(Gvn::GvnType t, OverridableCallable c) {
this.hasSubsumedQualifierType(t) and
hasCallable(any(OverridableCallable oc | oc = this.getAStaticTargetExt()), t, c)
}
/**
@@ -357,12 +347,33 @@ private module Internal {
}
pragma[nomagic]
private Callable getASubsumedStaticTarget0(Type t) {
private predicate contextArgHasConstrainedTypeParameterType(
DispatchCall ctx, Unification::ConstrainedTypeParameter tp
) {
this.contextArgHasType(ctx, tp, false)
}
pragma[nomagic]
private predicate contextArgHasUnconstrainedTypeParameterType(DispatchCall ctx) {
this.contextArgHasType(ctx, any(Unification::UnconstrainedTypeParameter t), false)
}
pragma[nomagic]
private predicate contextArgHasNonTypeParameterType(DispatchCall ctx, Gvn::GvnType t) {
exists(Type t0 |
this.contextArgHasType(ctx, t0, false) and
not t0 instanceof TypeParameter and
t = Gvn::getGlobalValueNumber(t0)
)
}
pragma[nomagic]
private Callable getASubsumedStaticTarget0(Gvn::GvnType t) {
exists(Callable staticTarget, Type declType |
staticTarget = this.getAStaticTarget() and
declType = staticTarget.getDeclaringType() and
result = staticTarget.getUnboundDeclaration() and
Unification::subsumes(declType, t)
Gvn::subsumes(Gvn::getGlobalValueNumber(declType), t)
)
}
@@ -375,7 +386,8 @@ private module Internal {
private Callable getASubsumedStaticTarget() {
result = this.getAStaticTarget()
or
result.getUnboundDeclaration() = this.getASubsumedStaticTarget0(result.getDeclaringType())
result.getUnboundDeclaration() =
this.getASubsumedStaticTarget0(Gvn::getGlobalValueNumber(result.getDeclaringType()))
}
/**
@@ -426,6 +438,12 @@ private module Internal {
)
}
pragma[noinline]
NonConstructedOverridableCallable getAViableOverrider0() {
getAPossibleType(this.getQualifier(), false) instanceof TypeParameter and
result.getAConstructingCallableOrSelf() = this.getAStaticTargetExt()
}
/**
* Gets a callable that is defined in a subtype of the qualifier type of this
* call, and which overrides a static target of this call.
@@ -468,9 +486,22 @@ private module Internal {
*/
private RuntimeCallable getAViableOverrider() {
exists(ValueOrRefType t, NonConstructedOverridableCallable c |
this.hasQualifierTypeOverridden(t, c.getAConstructingCallableOrSelf()) and
this.hasSubsumedQualifierTypeOverridden(Gvn::getGlobalValueNumber(t),
c.getAConstructingCallableOrSelf()) and
result = c.getAnOverrider(t)
)
or
exists(NonConstructedOverridableCallable c |
c = this.getAViableOverrider0() and
result = c.getAnOverrider(_)
|
this.hasUnconstrainedTypeParameterQualifierType()
or
exists(Unification::ConstrainedTypeParameter tp |
this.hasConstrainedTypeParameterQualifierType(tp) and
tp.subsumes(result.getDeclaringType())
)
)
}
override RuntimeCallable getADynamicTarget() {
@@ -510,36 +541,40 @@ private module Internal {
}
pragma[nomagic]
private RuntimeCallable getAViableOverriderInCallContext0(
NonConstructedOverridableCallable c, ValueOrRefType t
) {
result = this.getAViableOverrider() and
this.contextArgHasType(_, _, false) and
result = c.getAnOverrider(t)
private RuntimeCallable getAViableOverriderInCallContext0(Gvn::GvnType t) {
exists(NonConstructedOverridableCallable c |
result = this.getAViableOverrider() and
this.contextArgHasType(_, _, false) and
result = c.getAnOverrider(any(Type t0 | t = Gvn::getGlobalValueNumber(t0))) and
this.getAStaticTarget() = c.getAConstructingCallableOrSelf()
)
}
pragma[nomagic]
private RuntimeCallable getAViableOverriderInCallContext1(
NonConstructedOverridableCallable c, DispatchCall ctx
) {
exists(ValueOrRefType t |
result = this.getAViableOverriderInCallContext0(c, t) and
exists(Type t0, Type t1 |
this.contextArgHasType(ctx, t0, false) and
t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()]
|
t = t1
or
Unification::subsumes(t1, t)
)
private predicate contextArgHasSubsumedType(DispatchCall ctx, Gvn::GvnType t) {
hasOverrider(_, t) and
exists(Gvn::GvnType t0 | this.contextArgHasNonTypeParameterType(ctx, t0) |
t = t0
or
Gvn::subsumes(t0, t)
)
}
pragma[nomagic]
private RuntimeCallable getAViableOverriderInCallContext(DispatchCall ctx) {
exists(NonConstructedOverridableCallable c |
result = this.getAViableOverriderInCallContext1(c, ctx) and
this.getAStaticTarget() = c.getAConstructingCallableOrSelf()
exists(Gvn::GvnType t |
result = this.getAViableOverriderInCallContext0(t) and
this.contextArgHasSubsumedType(ctx, t)
)
or
result = this.getAViableOverrider() and
(
this.contextArgHasUnconstrainedTypeParameterType(ctx)
or
exists(Unification::ConstrainedTypeParameter tp |
this.contextArgHasConstrainedTypeParameterType(ctx, tp) and
tp.subsumes(result.getDeclaringType())
)
)
}

View File

@@ -111,13 +111,24 @@ module HardcodedCredentials {
}
/**
* Gets a regular expression for matching names of locations (variables, parameters, keys) that
* indicate the value being held is a credential.
* An assignable whose name indicates that the value being held is a credential.
*/
private string getACredentialRegex() {
result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or
result = "(?i).*(puid|username|userid).*" or
result = "(?i).*(cert)(?!.*(format|name)).*"
private class CredentialVar extends Assignable {
pragma[noinline]
CredentialVar() {
exists(string name | name = this.getName() |
name.regexpMatch("(?i).*pass(wd|word|code|phrase)(?!.*question).*")
or
name.regexpMatch("(?i).*(puid|username|userid).*")
or
name.regexpMatch("(?i).*(cert)(?!.*(format|name)).*")
)
}
}
private class CredentialVariableAccess extends VariableAccess {
pragma[noinline]
CredentialVariableAccess() { this.getTarget() instanceof CredentialVar }
}
/**
@@ -128,11 +139,11 @@ module HardcodedCredentials {
) {
// An argument to a library call that looks like a credential
// "...flows to the [Username] parameter in [call to method CreateUser]"
exists(Call call |
exists(Call call, CredentialVar param |
supplementaryElement = call and
description = "the $@ parameter in $@" and
sink = call.getArgumentForName(sinkName) and
sinkName.regexpMatch(getACredentialRegex()) and
sink = call.getArgumentForParameter(param) and
sinkName = param.getName() and
call.getTarget().fromLibrary()
)
or
@@ -144,22 +155,20 @@ module HardcodedCredentials {
description = "the $@ in $@" and
sink = call.getArgument(0) and
sinkName = "setter call argument" and
p.getName().regexpMatch(getACredentialRegex()) and
p instanceof CredentialVar and
p.fromLibrary()
)
or
// Sink compared to password variable
// "...flows to [] which is compared against [access of UserName]"
exists(ComparisonTest ct, VariableAccess credentialAccess, string varName |
exists(ComparisonTest ct, CredentialVariableAccess credentialAccess |
sinkName = sink.toString() and
supplementaryElement = credentialAccess and
description = "$@ which is compared against $@" and
ct.getAnArgument() = credentialAccess and
ct.getAnArgument() = sink and
ct.getComparisonKind().isEquality() and
not sink = credentialAccess and
varName = credentialAccess.getTarget().getName() and
varName.regexpMatch(getACredentialRegex())
not sink = credentialAccess
)
}

View File

@@ -20,3 +20,15 @@ class TextFieldSource extends LocalUserInputSource {
override string getSourceType() { result = "TextBox text" }
}
/** A call to any `System.Console.Read*` method. */
class SystemConsoleReadSource extends LocalUserInputSource {
SystemConsoleReadSource() {
this.asExpr() =
any(MethodCall call |
call.getTarget().hasQualifiedName("System.Console", ["ReadLine", "Read", "ReadKey"])
)
}
override string getSourceType() { result = "System.Console input" }
}

View File

@@ -1,2 +1,3 @@
compilationMessages
extractorMessages
| file://:0:0:0:0 | Extracting default argument value 'object RecordNumber = default' instead of 'object RecordNumber = -1'. The latter is not supported in C#. |

View File

@@ -0,0 +1 @@
| 4 |

View File

@@ -0,0 +1 @@
Metrics/Summaries/LinesOfCode.ql

View File

@@ -0,0 +1,14 @@
class C1
{
/*
int M()
{
return 0;
}
*/
// int M() => 0;
int M() => 0; // Comment
}

View File

@@ -0,0 +1,13 @@
using System;
using System;
public class Program
{
public static void Main()
{
var format = Console.ReadLine();
// BAD: Uncontrolled format string.
var x = string.Format(format, 1, 2);
}
}

View File

@@ -1,8 +1,11 @@
edges
| ConsoleUncontrolledFormatString.cs:8:22:8:39 | call to method ReadLine : String | ConsoleUncontrolledFormatString.cs:11:31:11:36 | access to local variable format |
| UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString : NameValueCollection | UncontrolledFormatString.cs:14:23:14:26 | access to local variable path |
| UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString : NameValueCollection | UncontrolledFormatString.cs:17:46:17:49 | access to local variable path |
| UncontrolledFormatStringBad.cs:9:25:9:47 | access to property QueryString : NameValueCollection | UncontrolledFormatStringBad.cs:12:39:12:44 | access to local variable format |
nodes
| ConsoleUncontrolledFormatString.cs:8:22:8:39 | call to method ReadLine : String | semmle.label | call to method ReadLine : String |
| ConsoleUncontrolledFormatString.cs:11:31:11:36 | access to local variable format | semmle.label | access to local variable format |
| UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
| UncontrolledFormatString.cs:14:23:14:26 | access to local variable path | semmle.label | access to local variable path |
| UncontrolledFormatString.cs:17:46:17:49 | access to local variable path | semmle.label | access to local variable path |
@@ -10,6 +13,7 @@ nodes
| UncontrolledFormatStringBad.cs:9:25:9:47 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection |
| UncontrolledFormatStringBad.cs:12:39:12:44 | access to local variable format | semmle.label | access to local variable format |
#select
| ConsoleUncontrolledFormatString.cs:11:31:11:36 | access to local variable format | ConsoleUncontrolledFormatString.cs:8:22:8:39 | call to method ReadLine : String | ConsoleUncontrolledFormatString.cs:11:31:11:36 | access to local variable format | $@ flows to here and is used as a format string. | ConsoleUncontrolledFormatString.cs:8:22:8:39 | call to method ReadLine | call to method ReadLine |
| UncontrolledFormatString.cs:14:23:14:26 | access to local variable path | UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString : NameValueCollection | UncontrolledFormatString.cs:14:23:14:26 | access to local variable path | $@ flows to here and is used as a format string. | UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString | access to property QueryString |
| UncontrolledFormatString.cs:17:46:17:49 | access to local variable path | UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString : NameValueCollection | UncontrolledFormatString.cs:17:46:17:49 | access to local variable path | $@ flows to here and is used as a format string. | UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString | access to property QueryString |
| UncontrolledFormatString.cs:34:23:34:31 | access to property Text | UncontrolledFormatString.cs:34:23:34:31 | access to property Text | UncontrolledFormatString.cs:34:23:34:31 | access to property Text | $@ flows to here and is used as a format string. | UncontrolledFormatString.cs:34:23:34:31 | access to property Text | access to property Text |

View File

@@ -259,8 +259,6 @@ This means that it is part of the output of the QL program.
Compiler pragmas
================
**Available for**: |characteristic predicates|, |member predicates|, |non-member predicates|
The following compiler pragmas affect the compilation and optimization of queries. You
should avoid using these annotations unless you experience significant performance issues.
@@ -284,6 +282,8 @@ predicates.
``pragma[inline]``
------------------
**Available for**: |characteristic predicates|, |member predicates|, |non-member predicates|
The ``pragma[inline]`` annotation tells the QL optimizer to always inline the annotated predicate
into the places where it is called. This can be useful when a predicate body is very expensive to
compute entirely, as it ensures that the predicate is evaluated with the other contextual information
@@ -292,6 +292,8 @@ at the places where it is called.
``pragma[noinline]``
--------------------
**Available for**: |characteristic predicates|, |member predicates|, |non-member predicates|
The ``pragma[noinline]`` annotation is used to prevent a predicate from being inlined into the
place where it is called. In practice, this annotation is useful when you've already grouped
certain variables together in a "helper" predicate, to ensure that the relation is evaluated
@@ -301,6 +303,8 @@ work of the helper predicate, so it's a good idea to annotate it with ``pragma[n
``pragma[nomagic]``
-------------------
**Available for**: |characteristic predicates|, |member predicates|, |non-member predicates|
The ``pragma[nomagic]`` annotation is used to prevent the QL optimizer from performing the "magic sets"
optimization on a predicate.
@@ -314,6 +318,8 @@ Note that ``nomagic`` implies ``noinline``.
``pragma[noopt]``
-----------------
**Available for**: |characteristic predicates|, |member predicates|, |non-member predicates|
The ``pragma[noopt]`` annotation is used to prevent the QL optimizer from optimizing a
predicate, except when it's absolutely necessary for compilation and evaluation to work.
@@ -364,7 +370,33 @@ When you use this annotation, be aware of the following issues:
succ.getSucc() = 3
)
}
``pragma[only_bind_out]``
-------------------------
**Available for**: |expressions|
The ``pragma[only_bind_out]`` annotation lets you specify the direction in which the QL compiler should bind expressions.
This can be useful to improve performance in rare cases where the QL optimizer orders parts of the QL program in an inefficient way.
For example, ``x = pragma[only_bind_out](y)`` is semantically equivalent to ``x = y``, but has different binding behavior.
``x = y`` binds ``x`` from ``y`` and vice versa, while ``x = pragma[only_bind_out](y)`` only binds ``x`` from ``y``.
For more information, see ":ref:`Binding <binding>`."
``pragma[only_bind_into]``
--------------------------
**Available for**: |expressions|
The ``pragma[only_bind_into]`` annotation lets you specify the direction in which the QL compiler should bind expressions.
This can be useful to improve performance in rare cases where the QL optimizer orders parts of the QL program in an inefficient way.
For example, ``x = pragma[only_bind_into](y)`` is semantically equivalent to ``x = y``, but has different binding behavior.
``x = y`` binds ``x`` from ``y`` and vice versa, while ``x = pragma[only_bind_into](y)`` only binds ``y`` from ``x``.
For more information, see ":ref:`Binding <binding>`."
.. _language:
Language pragmas
@@ -413,4 +445,5 @@ The ``bindingset`` annotation takes a comma-separated list of variables.
.. |fields| replace:: :ref:`fields <fields>`
.. |modules| replace:: :ref:`modules <modules>`
.. |aliases| replace:: :ref:`aliases <aliases>`
.. |algebraic datatypes| replace:: :ref:`algebraic datatypes <algebraic-datatypes>`
.. |algebraic datatypes| replace:: :ref:`algebraic datatypes <algebraic-datatypes>`
.. |expressions| replace:: :ref:`expressions <expressions>`

View File

@@ -1116,8 +1116,6 @@ A super expression may only occur in a QL program as the receiver expression for
If a super expression includes a ``type``, then that type must be a class that the enclosing class inherits from.
If the super expression does not include a type, then the enclosing class must have a single declared base type, and that base type must be a class.
The value of a super expression is the same as the value of ``this`` in the named tuple.
Casts
@@ -1169,7 +1167,12 @@ A valid call with results *resolves* to a set of predicates. The ways a call can
- If the call has no receiver and the predicate name is a selection identifier, then the qualifier is resolved as a module (see "`Module resolution <#module-resolution>`__"). The identifier is then resolved in the exported predicate environment of the qualifier module.
- If the call has a super expression as the receiver, then it resolves to a member predicate in a class the enclosing class inherits from. If the super expression is unqualified, then the super-class is the single class that the current class inherits from. If there is not exactly one such class, then the program is invalid. Otherwise the super-class is the class named by the qualifier of the super expression. The predicate is resolved by looking up its name and arity in the exported predicate environment of the super-class.
- If the call has a super expression as the receiver, then it resolves to a member predicate in a class that the enclosing class inherits from:
- If the super expression is unqualified and there is a single class that the current class inherits from, then the super-class is that class.
- If the super expression is unqualified and there are multiple classes that the current class inherits from, then the super-class is the domain type.
- Otherwise, the super-class is the class named by the qualifier of the super expression.
The predicate is resolved by looking up its name and arity in the exported predicate environment of the super-class.
- If the type of the receiver is the same as the enclosing class, the predicate is resolved by looking up its name and arity in the visible predicate environment of the class.

View File

@@ -23,6 +23,7 @@ C# built-in support
ASP.NET, Web application framework
ASP.NET Core, Web application framework
ASP.NET Razor templates, Web application framework
Dapper, Database ORM
EntityFramework, Database ORM
EntityFramework Core, Database ORM
Json.NET, Serialization

View File

@@ -0,0 +1,70 @@
/**
* Provides classes and predicates for reporting extractor diagnostics to end users.
*/
import java
/** Gets the SARIF severity level that indicates an error. */
private int getErrorSeverity() { result = 2 }
/** Gets the SARIF severity level that indicates a warning. */
private int getWarnSeverity() { result = 1 }
private predicate knownWarnings(@diagnostic d, string msg, int sev) {
exists(string filename |
diagnostics(d, 2, _, "Skipping Lombok-ed source file: " + filename, _, _) and
msg = "Use of Lombok detected. Skipping file: " + filename and
sev = getWarnSeverity()
)
}
private predicate knownErrors(@diagnostic d, string msg, int sev) {
exists(string numErr, Location l |
diagnostics(d, 6, _, numErr, _, l) and
msg = "Frontend errors in file: " + l.getFile().getAbsolutePath() + " (" + numErr + ")" and
sev = getErrorSeverity()
)
or
exists(string filename, Location l |
diagnostics(d, 7, _, "Exception compiling file " + filename, _, l) and
msg = "Extraction incomplete in file: " + filename and
sev = getErrorSeverity()
)
or
exists(string errMsg, Location l |
diagnostics(d, 8, _, errMsg, _, l) and
msg = "Severe error: " + errMsg and
sev = getErrorSeverity()
)
}
private predicate unknownErrors(@diagnostic d, string msg, int sev) {
not knownErrors(d, _, _) and
exists(Location l, File f, int diagSev |
diagnostics(d, diagSev, _, _, _, l) and l.getFile() = f and diagSev > 3
|
exists(f.getRelativePath()) and
msg = "Unknown errors in file: " + f.getAbsolutePath() + " (" + diagSev + ")" and
sev = getErrorSeverity()
)
}
/**
* Holds if an extraction error or warning occurred that should be reported to end users,
* with the error message `msg` and SARIF severity `sev`.
*/
predicate reportableDiagnostics(@diagnostic d, string msg, int sev) {
knownWarnings(d, msg, sev) or knownErrors(d, msg, sev) or unknownErrors(d, msg, sev)
}
/**
* Holds if compilation unit `f` is a source file that has
* no relevant extraction diagnostics associated with it.
*/
predicate successfullyExtracted(CompilationUnit f) {
not exists(@diagnostic d, Location l |
reportableDiagnostics(d, _, _) and diagnostics(d, _, _, _, _, l) and l.getFile() = f
) and
exists(f.getRelativePath()) and
f.fromSource()
}

View File

@@ -0,0 +1,13 @@
/**
* @name Extraction errors
* @description A list of extraction errors for files in the source code directory.
* @kind diagnostic
* @id java/diagnostics/extraction-errors
*/
import java
import DiagnosticsReporting
from string msg, int sev
where reportableDiagnostics(_, msg, sev)
select msg, sev

View File

@@ -0,0 +1,14 @@
/**
* @name Successfully extracted files
* @description A list of all files in the source code directory that
* were extracted without encountering an error in the file.
* @kind diagnostic
* @id java/diagnostics/successfully-extracted-files
*/
import java
import DiagnosticsReporting
from CompilationUnit f
where successfullyExtracted(f)
select f, ""

View File

@@ -0,0 +1,13 @@
/**
* @id java/summary/lines-of-code
* @name Total lines of code in the database
* @description The total number of lines of code across all files. This is a useful metric of the size of a database.
* For all files that were seen during the build, this query counts the lines of code, excluding whitespace
* or comments.
* @kind metric
* @tags summary
*/
import java
select sum(CompilationUnit f | f.fromSource() | f.getNumberOfLinesOfCode())

View File

@@ -0,0 +1,81 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
Apache Groovy is a powerful, optionally typed and dynamic language,
with static-typing and static compilation capabilities.
It integrates smoothly with any Java program,
and immediately delivers to your application powerful features,
including scripting capabilities, Domain-Specific Language authoring,
runtime and compile-time meta-programming and functional programming.
If a Groovy script is built using attacker-controlled data,
and then evaluated, then it may allow the attacker to achieve RCE.
</p>
</overview>
<recommendation>
<p>
It is generally recommended to avoid using untrusted input in a Groovy evaluation.
If this is not possible, use a sandbox solution. Developers must also take care that Groovy
compile-time metaprogramming can also lead to RCE: it is possible to achieve RCE by compiling
a Groovy script (see the article "Abusing Meta Programming for Unauthenticated RCE!" linked below).
Groovy's <code>SecureASTCustomizer</code> allows securing source code by controlling what code constructs are permitted.
This is typically done when using Groovy for its scripting or domain specific language (DSL) features.
The fundamental problem is that Groovy is a dynamic language, yet <code>SecureASTCustomizer</code> works by looking at Groovy AST statically.
This makes it very easy for an attacker to bypass many of the intended checks
(see https://kohsuke.org/2012/04/27/groovy-secureastcustomizer-is-harmful/).
Therefore, besides <code>SecureASTCustomizer</code>, runtime checks are also necessary before calling Groovy methods
(see https://melix.github.io/blog/2015/03/sandboxing.html).
It is also possible to use a block-list method, excluding unwanted classes from being loaded by the JVM.
This method is not always recommended, because block-lists can be bypassed by unexpected values.
</p>
</recommendation>
<example>
<p>
The following example uses untrusted data to evaluate a Groovy script.
</p>
<sample src="GroovyInjectionBad.java" />
<p>
The following example uses classloader block-list approach to exclude loading dangerous classes.
</p>
<sample src="GroovyInjectionBlocklist.java" />
</example>
<references>
<li>
Orange Tsai:
<a href="https://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html">Abusing Meta Programming for Unauthenticated RCE!</a>.
</li>
<li>
Cédric Champeau:
<a href="https://melix.github.io/blog/2015/03/sandboxing.html">Improved sandboxing of Groovy scripts</a>.
</li>
<li>
Kohsuke Kawaguchi:
<a href="https://kohsuke.org/2012/04/27/groovy-secureastcustomizer-is-harmful/">Groovy SecureASTCustomizer is harmful</a>.
</li>
<li>
Welk1n:
<a href="https://github.com/welk1n/exploiting-groovy-in-Java/">Groovy Injection payloads</a>.
</li>
<li>
Charles Chan:
<a href="https://levelup.gitconnected.com/secure-groovy-script-execution-in-a-sandbox-ea39f80ee87/">Secure Groovy Script Execution in a Sandbox</a>.
</li>
<li>
Eugene:
<a href="https://stringconcat.com/en/scripting-and-sandboxing/">Scripting and sandboxing in a JVM environment</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,20 @@
/**
* @name Groovy Language injection
* @description Evaluation of a user-controlled Groovy script
* may lead to arbitrary code execution.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/groovy-injection
* @tags security
* external/cwe/cwe-094
*/
import java
import DataFlow::PathGraph
import GroovyInjectionLib
from DataFlow::PathNode source, DataFlow::PathNode sink, GroovyInjectionConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Groovy Injection from $@.", source.getNode(),
"this user input"

View File

@@ -0,0 +1,27 @@
public class GroovyInjection {
void injectionViaClassLoader(HttpServletRequest request) {
String script = request.getParameter("script");
final GroovyClassLoader classLoader = new GroovyClassLoader();
Class groovy = classLoader.parseClass(script);
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
}
void injectionViaEval(HttpServletRequest request) {
String script = request.getParameter("script");
Eval.me(script);
}
void injectionViaGroovyShell(HttpServletRequest request) {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script);
}
void injectionViaGroovyShellGroovyCodeSource(HttpServletRequest request) {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
shell.evaluate(gcs);
}
}

View File

@@ -0,0 +1,17 @@
public class SandboxGroovyClassLoader extends ClassLoader {
public SandboxGroovyClassLoader(ClassLoader parent) {
super(parent);
}
/* override `loadClass` here to prevent loading sensitive classes, such as `java.lang.Runtime`, `java.lang.ProcessBuilder`, `java.lang.System`, etc. */
/* Note we must also block `groovy.transform.ASTTest`, `groovy.lang.GrabConfig` and `org.buildobjects.process.ProcBuilder` to prevent compile-time RCE. */
static void runWithSandboxGroovyClassLoader() throws Exception {
// GOOD: route all class-loading via sand-boxing classloader.
SandboxGroovyClassLoader classLoader = new GroovyClassLoader(new SandboxGroovyClassLoader());
Class<?> scriptClass = classLoader.parseClass(untrusted.getQueryString());
Object scriptInstance = scriptClass.newInstance();
Object result = scriptClass.getDeclaredMethod("bar", new Class[]{}).invoke(scriptInstance, new Object[]{});
}
}

View File

@@ -0,0 +1,160 @@
/**
* Provides classes and predicates for Groovy Code Injection
* taint-tracking configuration.
*/
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
/** A data flow sink for Groovy expression injection vulnerabilities. */
abstract private class GroovyInjectionSink extends DataFlow::ExprNode { }
/**
* A taint-tracking configuration for unsafe user input
* that is used to evaluate a Groovy expression.
*/
class GroovyInjectionConfig extends TaintTracking::Configuration {
GroovyInjectionConfig() { this = "GroovyInjectionConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof GroovyInjectionSink }
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
groovyCodeSourceTaintStep(fromNode, toNode)
}
}
/** The class `groovy.lang.GroovyShell`. */
private class TypeGroovyShell extends RefType {
TypeGroovyShell() { this.hasQualifiedName("groovy.lang", "GroovyShell") }
}
/** The class `groovy.lang.GroovyCodeSource`. */
private class TypeGroovyCodeSource extends RefType {
TypeGroovyCodeSource() { this.hasQualifiedName("groovy.lang", "GroovyCodeSource") }
}
/**
* Methods in the `GroovyShell` class that evaluate a Groovy expression.
*/
private class GroovyShellMethod extends Method {
GroovyShellMethod() {
this.getDeclaringType() instanceof TypeGroovyShell and
this.getName() in ["evaluate", "parse", "run"]
}
}
private class GroovyShellMethodAccess extends MethodAccess {
GroovyShellMethodAccess() { this.getMethod() instanceof GroovyShellMethod }
}
/**
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted string to
* a `GroovyCodeSource` instance, i.e. `new GroovyCodeSource(tainted, ...)`.
*/
private predicate groovyCodeSourceTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
exists(ConstructorCall gcscc |
gcscc.getConstructedType() instanceof TypeGroovyCodeSource and
gcscc = toNode.asExpr() and
gcscc.getArgument(0) = fromNode.asExpr()
)
}
/**
* A sink for Groovy Injection via the `GroovyShell` class.
*
* ```
* GroovyShell gs = new GroovyShell();
* gs.evaluate(sink, ....)
* gs.run(sink, ....)
* gs.parse(sink,...)
* ```
*/
private class GroovyShellSink extends GroovyInjectionSink {
GroovyShellSink() {
exists(GroovyShellMethodAccess ma, Argument firstArg |
ma.getArgument(0) = firstArg and
firstArg = this.asExpr() and
(
firstArg.getType() instanceof TypeString or
firstArg.getType() instanceof TypeGroovyCodeSource
)
)
}
}
/** The class `groovy.util.Eval`. */
private class TypeEval extends RefType {
TypeEval() { this.hasQualifiedName("groovy.util", "Eval") }
}
/**
* Methods in the `Eval` class that evaluate a Groovy expression.
*/
private class EvalMethod extends Method {
EvalMethod() {
this.getDeclaringType() instanceof TypeEval and
this.getName() in ["me", "x", "xy", "xyz"]
}
}
private class EvalMethodAccess extends MethodAccess {
EvalMethodAccess() { this.getMethod() instanceof EvalMethod }
Expr getArgumentExpr() { result = this.getArgument(this.getNumArgument() - 1) }
}
/**
* A sink for Groovy Injection via the `Eval` class.
*
* ```
* Eval.me(sink)
* Eval.me("p1", "p2", sink)
* Eval.x("p1", sink)
* Eval.xy("p1", "p2" sink)
* Eval.xyz("p1", "p2", "p3", sink)
* ```
*/
private class EvalSink extends GroovyInjectionSink {
EvalSink() { exists(EvalMethodAccess ma | ma.getArgumentExpr() = this.asExpr()) }
}
/** The class `groovy.lang.GroovyClassLoader`. */
private class TypeGroovyClassLoader extends RefType {
TypeGroovyClassLoader() { this.hasQualifiedName("groovy.lang", "GroovyClassLoader") }
}
/**
* A method in the `GroovyClassLoader` class that evaluates a Groovy expression.
*/
private class GroovyClassLoaderParseClassMethod extends Method {
GroovyClassLoaderParseClassMethod() {
this.getDeclaringType() instanceof TypeGroovyClassLoader and
this.hasName("parseClass")
}
}
private class GroovyClassLoaderParseClassMethodAccess extends MethodAccess {
GroovyClassLoaderParseClassMethodAccess() {
this.getMethod() instanceof GroovyClassLoaderParseClassMethod
}
}
/**
* A sink for Groovy Injection via the `GroovyClassLoader` class.
*
* ```
* GroovyClassLoader classLoader = new GroovyClassLoader();
* Class groovy = classLoader.parseClass(script);
* ```
*
* Groovy supports compile-time metaprogramming, so just calling the `parseClass`
* method is enough to achieve RCE.
*/
private class GroovyClassLoadParseClassSink extends GroovyInjectionSink {
GroovyClassLoadParseClassSink() {
exists(GroovyClassLoaderParseClassMethodAccess ma | ma.getArgument(0) = this.asExpr())
}
}

View File

@@ -3,6 +3,7 @@
*/
import Member
import semmle.code.java.security.ExternalProcess
// --- Standard types ---
/** The class `java.lang.Object`. */
@@ -176,24 +177,37 @@ class TypeFile extends Class {
}
// --- Standard methods ---
/**
* Any constructor of class `java.lang.ProcessBuilder`.
*/
class ProcessBuilderConstructor extends Constructor, ExecCallable {
ProcessBuilderConstructor() { this.getDeclaringType() instanceof TypeProcessBuilder }
override int getAnExecutedArgument() { result = 0 }
}
/**
* Any of the methods named `command` on class `java.lang.ProcessBuilder`.
*/
class MethodProcessBuilderCommand extends Method {
class MethodProcessBuilderCommand extends Method, ExecCallable {
MethodProcessBuilderCommand() {
hasName("command") and
getDeclaringType() instanceof TypeProcessBuilder
}
override int getAnExecutedArgument() { result = 0 }
}
/**
* Any method named `exec` on class `java.lang.Runtime`.
*/
class MethodRuntimeExec extends Method {
class MethodRuntimeExec extends Method, ExecCallable {
MethodRuntimeExec() {
hasName("exec") and
getDeclaringType() instanceof TypeRuntime
}
override int getAnExecutedArgument() { result = 0 }
}
/**

View File

@@ -18,7 +18,9 @@ abstract class Modifiable extends Element {
* Holds if this element has modifier `m`.
*
* For most purposes, the more specialized predicates `isAbstract`, `isPublic`, etc.
* should be used, which also take implicit modifiers into account.
* should be used.
*
* Both this method and those specialized predicates take implicit modifiers into account.
* For instance, non-default instance methods in interfaces are implicitly
* abstract, so `isAbstract()` will hold for them even if `hasModifier("abstract")`
* does not.

View File

@@ -67,6 +67,7 @@
import java
private import semmle.code.java.dataflow.DataFlow::DataFlow
private import internal.DataFlowPrivate
private import FlowSummary
/**
* A module importing the frameworks that provide external flow data,
@@ -76,6 +77,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.ApacheHttp
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.security.LdapInjection
}
private predicate sourceModelCsv(string row) {
@@ -459,7 +461,8 @@ module CsvValidation {
summaryModel(_, _, _, _, _, _, input, _, _) and pred = "summary"
|
specSplit(input, part, _) and
not part.regexpMatch("|Argument|ReturnValue") and
not part.regexpMatch("|ReturnValue|ArrayElement|Element|MapKey|MapValue") and
not (part = "Argument" and pred = "sink") and
not parseArg(part, _) and
msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
)
@@ -470,7 +473,8 @@ module CsvValidation {
summaryModel(_, _, _, _, _, _, _, output, _) and pred = "summary"
|
specSplit(output, part, _) and
not part.regexpMatch("|Argument|Parameter|ReturnValue") and
not part.regexpMatch("|ReturnValue|ArrayElement|Element|MapKey|MapValue") and
not (part = ["Argument", "Parameter"] and pred = "source") and
not parseArg(part, _) and
not parseParam(part, _) and
msg = "Unrecognized output specification \"" + part + "\" in " + pred + " model."
@@ -675,6 +679,75 @@ private predicate summaryElementRef(Top ref, string input, string output, string
)
}
private SummaryComponent interpretComponent(string c) {
specSplit(_, c, _) and
(
exists(int pos | parseArg(c, pos) and result = SummaryComponent::argument(pos))
or
exists(int pos | parseParam(c, pos) and result = SummaryComponent::parameter(pos))
or
c = "ReturnValue" and result = SummaryComponent::return()
or
c = "ArrayElement" and result = SummaryComponent::content(any(ArrayContent c0))
or
c = "Element" and result = SummaryComponent::content(any(CollectionContent c0))
or
c = "MapKey" and result = SummaryComponent::content(any(MapKeyContent c0))
or
c = "MapValue" and result = SummaryComponent::content(any(MapValueContent c0))
)
}
private predicate interpretSpec(string spec, int idx, SummaryComponentStack stack) {
exists(string c |
summaryElement(_, spec, _, _) or
summaryElement(_, _, spec, _)
|
len(spec, idx + 1) and
specSplit(spec, c, idx) and
stack = SummaryComponentStack::singleton(interpretComponent(c))
)
or
exists(SummaryComponent head, SummaryComponentStack tail |
interpretSpec(spec, idx, head, tail) and
stack = SummaryComponentStack::push(head, tail)
)
}
private predicate interpretSpec(
string output, int idx, SummaryComponent head, SummaryComponentStack tail
) {
exists(string c |
interpretSpec(output, idx + 1, tail) and
specSplit(output, c, idx) and
head = interpretComponent(c)
)
}
private class MkStack extends RequiredSummaryComponentStack {
MkStack() { interpretSpec(_, _, _, this) }
override predicate required(SummaryComponent c) { interpretSpec(_, _, c, this) }
}
private class SummarizedCallableExternal extends SummarizedCallable {
SummarizedCallableExternal() { summaryElement(this, _, _, _) }
override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
exists(string inSpec, string outSpec, string kind |
summaryElement(this, inSpec, outSpec, kind) and
interpretSpec(inSpec, 0, input) and
interpretSpec(outSpec, 0, output)
|
kind = "value" and preservesValue = true
or
kind = "taint" and preservesValue = false
)
}
}
private newtype TAstOrNode =
TAst(Top t) or
TNode(Node n)
@@ -761,15 +834,3 @@ predicate sinkNode(Node node, string kind) {
interpretInput(input, 0, ref, TNode(node))
)
}
/**
* Holds if `node1` to `node2` is specified as a flow step with the given kind
* in a CSV flow model.
*/
predicate summaryStep(Node node1, Node node2, string kind) {
exists(Top ref, string input, string output |
summaryElementRef(ref, input, output, kind) and
interpretInput(input, 0, ref, TNode(node1)) and
interpretOutput(output, 0, ref, TNode(node2))
)
}

View File

@@ -7,8 +7,10 @@ private import internal.FlowSummaryImpl as Impl
private import internal.DataFlowDispatch
private import internal.DataFlowPrivate
// import all instances below
private module Summaries { }
// import all instances of SummarizedCallable below
private module Summaries {
private import semmle.code.java.dataflow.ExternalFlow
}
class SummaryComponent = Impl::Public::SummaryComponent;

View File

@@ -84,8 +84,10 @@ private predicate instanceFieldAssign(Expr src, FieldAccess fa) {
private newtype TContent =
TFieldContent(InstanceField f) or
TArrayContent() or
TCollectionContent() or
TArrayContent()
TMapKeyContent() or
TMapValueContent()
/**
* A reference contained in an object. Examples include instance fields, the
@@ -114,12 +116,20 @@ class FieldContent extends Content, TFieldContent {
}
}
class CollectionContent extends Content, TCollectionContent {
override string toString() { result = "collection" }
class ArrayContent extends Content, TArrayContent {
override string toString() { result = "[]" }
}
class ArrayContent extends Content, TArrayContent {
override string toString() { result = "array" }
class CollectionContent extends Content, TCollectionContent {
override string toString() { result = "<element>" }
}
class MapKeyContent extends Content, TMapKeyContent {
override string toString() { result = "<map.key>" }
}
class MapValueContent extends Content, TMapValueContent {
override string toString() { result = "<map.value>" }
}
/**

View File

@@ -142,8 +142,6 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
or
node2.asExpr().(AssignExpr).getSource() = node1.asExpr()
or
summaryStep(node1, node2, "value")
or
exists(MethodAccess ma, ValuePreservingMethod m, int argNo |
ma.getCallee().getSourceDeclaration() = m and m.returnsValue(argNo)
|

View File

@@ -446,7 +446,19 @@ module Private {
summary(c, inputContents, outputContents, preservesValue) and
pred = summaryNodeInputState(c, inputContents) and
succ = summaryNodeOutputState(c, outputContents)
|
preservesValue = true
or
preservesValue = false and not summary(c, inputContents, outputContents, true)
)
or
// If flow through a method updates a parameter from some input A, and that
// parameter also is returned through B, then we'd like a combined flow from A
// to B as well. As an example, this simplifies modeling of fluent methods:
// for `StringBuilder.append(x)` with a specified value flow from qualifier to
// return value and taint flow from argument 0 to the qualifier, then this
// allows us to infer taint flow from argument 0 to the return value.
summaryPostUpdateNode(pred, succ) and preservesValue = true
}
/**

View File

@@ -46,20 +46,11 @@ predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
* different objects.
*/
predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalBasicTaintStep(src, sink)
or
composedValueAndTaintModelStep(src, sink)
}
private predicate localAdditionalBasicTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
or
localAdditionalTaintUpdateStep(src.asExpr(),
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
or
summaryStep(src, sink, "taint") and
not summaryStep(src, sink, "value")
or
exists(Argument arg |
src.asExpr() = arg and
arg.isVararg() and
@@ -69,26 +60,6 @@ private predicate localAdditionalBasicTaintStep(DataFlow::Node src, DataFlow::No
FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
}
/**
* Holds if an additional step from `src` to `sink` through a call can be inferred from the
* combination of a value-preserving step providing an alias between an input and the output
* and a taint step from `src` to one the aliased nodes. For example, if we know that `f(a, b)` returns
* the exact value of `a` and also propagates taint from `b` to `a`, then we also know that
* the return value is tainted after `f` completes.
*/
private predicate composedValueAndTaintModelStep(ArgumentNode src, DataFlow::Node sink) {
exists(Call call, ArgumentNode valueSource, DataFlow::PostUpdateNode valueSourcePost |
src.argumentOf(call, _) and
valueSource.argumentOf(call, _) and
src != valueSource and
valueSourcePost.getPreUpdateNode() = valueSource and
// in-x -value-> out-y and in-z -taint-> in-x ==> in-z -taint-> out-y
localAdditionalBasicTaintStep(src, valueSourcePost) and
DataFlow::localFlowStep(valueSource, DataFlow::exprNode(call)) and
sink = DataFlow::exprNode(call)
)
}
/**
* Holds if the additional step from `src` to `sink` should be included in all
* global taint flow configurations.

View File

@@ -149,9 +149,8 @@ private class ApacheHttpFlowStep extends SummaryModelCsv {
"org.apache.hc.core5.http.message;RequestLine;true;getMethod;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;getUri;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;toString;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(HttpRequest);;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(String,String,ProtocolVersion);;Argument[1];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(String,String,ProtocolVersion);;Argument[1];ReturnValue;taint",
"org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(HttpRequest);;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(String,String,ProtocolVersion);;Argument[1];Argument[-1];taint",
"org.apache.hc.core5.function;Supplier;true;get;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.net;URIAuthority;true;getHostName;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.net;URIAuthority;true;toString;();;Argument[-1];ReturnValue;taint",
@@ -181,16 +180,16 @@ private class ApacheHttpFlowStep extends SummaryModelCsv {
"org.apache.hc.core5.http.io.entity;HttpEntities;true;withTrailers;;;Argument[0];ReturnValue;taint",
"org.apache.http.entity;BasicHttpEntity;true;setContent;(InputStream);;Argument[0];Argument[-1];taint",
"org.apache.http.entity;BufferedHttpEntity;true;BufferedHttpEntity;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.http.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];ReturnValue;taint",
"org.apache.http.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];Argument[-1];taint",
"org.apache.http.entity;HttpEntityWrapper;true;HttpEntityWrapper;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.http.entity;InputStreamEntity;true;InputStreamEntity;;;Argument[0];ReturnValue;taint",
"org.apache.http.entity;StringEntity;true;StringEntity;;;Argument[0];ReturnValue;taint",
"org.apache.http.entity;StringEntity;true;StringEntity;;;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.http.io.entity;BasicHttpEntity;true;BasicHttpEntity;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;BufferedHttpEntity;true;BufferedHttpEntity;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];Argument[-1];taint",
"org.apache.hc.core5.http.io.entity;HttpEntityWrapper;true;HttpEntityWrapper;(HttpEntity);;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;InputStreamEntity;true;InputStreamEntity;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;StringEntity;true;StringEntity;;;Argument[0];ReturnValue;taint",
"org.apache.hc.core5.http.io.entity;StringEntity;true;StringEntity;;;Argument[0];Argument[-1];taint",
"org.apache.http.util;ByteArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.http.util;ByteArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint",
"org.apache.http.util;ByteArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint",

View File

@@ -1,20 +1,28 @@
/* Definitions related to the Apache Commons Exec library. */
import semmle.code.java.Type
import semmle.code.java.security.ExternalProcess
library class TypeCommandLine extends Class {
/** The class `org.apache.commons.exec.CommandLine`. */
private class TypeCommandLine extends Class {
TypeCommandLine() { hasQualifiedName("org.apache.commons.exec", "CommandLine") }
}
library class MethodCommandLineParse extends Method {
/** The `parse()` method of the class `org.apache.commons.exec.CommandLine`. */
private class MethodCommandLineParse extends Method, ExecCallable {
MethodCommandLineParse() {
getDeclaringType() instanceof TypeCommandLine and
hasName("parse")
}
override int getAnExecutedArgument() { result = 0 }
}
library class MethodCommandLineAddArguments extends Method {
/** The `addArguments()` method of the class `org.apache.commons.exec.CommandLine`. */
private class MethodCommandLineAddArguments extends Method, ExecCallable {
MethodCommandLineAddArguments() {
getDeclaringType() instanceof TypeCommandLine and
hasName("addArguments")
}
override int getAnExecutedArgument() { result = 0 }
}

View File

@@ -626,12 +626,12 @@ private class ApacheObjectUtilsModel extends SummaryModelCsv {
"org.apache.commons.lang3;ObjectUtils;false;CONST_BYTE;;;Argument[0];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;CONST_SHORT;;;Argument[0];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;defaultIfNull;;;Argument[0..1];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;firstNonNull;;;Argument[0];ReturnValue;taint",
"org.apache.commons.lang3;ObjectUtils;false;firstNonNull;;;ArrayElement of Argument[0];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;getIfNull;;;Argument[0];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;max;;;Argument[0];ReturnValue;taint",
"org.apache.commons.lang3;ObjectUtils;false;median;;;Argument[0];ReturnValue;taint",
"org.apache.commons.lang3;ObjectUtils;false;min;;;Argument[0];ReturnValue;taint",
"org.apache.commons.lang3;ObjectUtils;false;mode;;;Argument[0];ReturnValue;taint",
"org.apache.commons.lang3;ObjectUtils;false;max;;;ArrayElement of Argument[0];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;median;;;ArrayElement of Argument[0];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;min;;;ArrayElement of Argument[0];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;mode;;;ArrayElement of Argument[0];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;requireNonEmpty;;;Argument[0];ReturnValue;value",
"org.apache.commons.lang3;ObjectUtils;false;toString;(Object,String);;Argument[1];ReturnValue;value"
]

View File

@@ -13,7 +13,8 @@ private class GuavaBaseCsv extends SummaryModelCsv {
"com.google.common.base;Strings;false;padStart;(String,int,char);;Argument[0];ReturnValue;taint",
"com.google.common.base;Strings;false;padEnd;(String,int,char);;Argument[0];ReturnValue;taint",
"com.google.common.base;Strings;false;repeat;(String,int);;Argument[0];ReturnValue;taint",
"com.google.common.base;Strings;false;lenientFormat;(String,Object[]);;Argument;ReturnValue;taint",
"com.google.common.base;Strings;false;lenientFormat;(String,Object[]);;Argument[0];ReturnValue;taint",
"com.google.common.base;Strings;false;lenientFormat;(String,Object[]);;ArrayElement of Argument[1];ReturnValue;taint",
"com.google.common.base;Joiner;false;on;(String);;Argument[0];ReturnValue;taint",
"com.google.common.base;Joiner;false;skipNulls;();;Argument[-1];ReturnValue;taint",
"com.google.common.base;Joiner;false;useForNull;(String);;Argument[-1];ReturnValue;taint",
@@ -22,14 +23,14 @@ private class GuavaBaseCsv extends SummaryModelCsv {
"com.google.common.base;Joiner;false;withKeyValueSeparator;(String);;Argument[-1];ReturnValue;taint",
"com.google.common.base;Joiner;false;withKeyValueSeparator;(char);;Argument[-1];ReturnValue;taint",
// Note: The signatures of some of the appendTo methods involve collection flow
"com.google.common.base;Joiner;false;appendTo;;;Argument;Argument[0];taint",
"com.google.common.base;Joiner;false;appendTo;;;Argument[-1..3];Argument[0];taint",
"com.google.common.base;Joiner;false;appendTo;;;Argument[0];ReturnValue;value",
"com.google.common.base;Joiner;false;join;;;Argument;ReturnValue;taint",
"com.google.common.base;Joiner;false;join;;;Argument[-1..2];ReturnValue;taint",
"com.google.common.base;Joiner$MapJoiner;false;useForNull;(String);;Argument[0];ReturnValue;taint",
"com.google.common.base;Joiner$MapJoiner;false;useForNull;(String);;Argument[-1];ReturnValue;taint",
"com.google.common.base;Joiner$MapJoiner;false;appendTo;;;Argument;Argument[0];taint",
"com.google.common.base;Joiner$MapJoiner;false;appendTo;;;Argument[1];Argument[0];taint",
"com.google.common.base;Joiner$MapJoiner;false;appendTo;;;Argument[0];ReturnValue;value",
"com.google.common.base;Joiner$MapJoiner;false;join;;;Argument;ReturnValue;taint",
"com.google.common.base;Joiner$MapJoiner;false;join;;;Argument[-1..0];ReturnValue;taint",
"com.google.common.base;Splitter;false;split;(CharSequence);;Argument[0];ReturnValue;taint",
"com.google.common.base;Splitter;false;splitToList;(CharSequence);;Argument[0];ReturnValue;taint",
"com.google.common.base;Splitter;false;splitToStream;(CharSequence);;Argument[0];ReturnValue;taint",

View File

@@ -61,7 +61,7 @@ private class GuavaIoCsv extends SummaryModelCsv {
"com.google.common.io;Files;false;simplifyPath;(String);;Argument[0];ReturnValue;taint",
"com.google.common.io;MoreFiles;false;getFileExtension;(Path);;Argument[0];ReturnValue;taint",
"com.google.common.io;MoreFiles;false;getNameWithoutExtension;(Path);;Argument[0];ReturnValue;taint",
"com.google.common.io;LineReader;false;LineReader;(Readable);;Argument[0];ReturnValue;taint",
"com.google.common.io;LineReader;false;LineReader;(Readable);;Argument[0];Argument[-1];taint",
"com.google.common.io;LineReader;true;readLine;();;Argument[-1];ReturnValue;taint",
"com.google.common.io;ByteArrayDataOutput;true;toByteArray;();;Argument[-1];ReturnValue;taint",
"com.google.common.io;ByteArrayDataOutput;true;write;(byte[]);;Argument[0];Argument[-1];taint",

View File

@@ -1,7 +1,20 @@
/* Definitions related to external processes. */
import semmle.code.java.Member
import semmle.code.java.JDK
import semmle.code.java.frameworks.apache.Exec
private module Instances {
private import semmle.code.java.JDK
private import semmle.code.java.frameworks.apache.Exec
}
/**
* A callable that executes a command.
*/
abstract class ExecCallable extends Callable {
/**
* Gets the index of an argument that will be part of the command that is executed.
*/
abstract int getAnExecutedArgument();
}
/**
* An expression used as an argument to a call that executes an external command. For calls to
@@ -10,21 +23,10 @@ import semmle.code.java.frameworks.apache.Exec
*/
class ArgumentToExec extends Expr {
ArgumentToExec() {
exists(MethodAccess execCall, Method method |
execCall.getArgument(0) = this and
method = execCall.getMethod() and
(
method instanceof MethodRuntimeExec or
method instanceof MethodProcessBuilderCommand or
method instanceof MethodCommandLineParse or
method instanceof MethodCommandLineAddArguments
)
)
or
exists(ConstructorCall expr, Constructor cons |
expr.getConstructor() = cons and
cons.getDeclaringType().hasQualifiedName("java.lang", "ProcessBuilder") and
expr.getArgument(0) = this
exists(Call execCall, ExecCallable execCallable, int i |
execCall.getArgument(pragma[only_bind_into](i)) = this and
execCallable = execCall.getCallee() and
i = execCallable.getAnExecutedArgument()
)
}
}

View File

@@ -6,6 +6,7 @@ import semmle.code.java.frameworks.Jndi
import semmle.code.java.frameworks.UnboundId
import semmle.code.java.frameworks.SpringLdap
import semmle.code.java.frameworks.ApacheLdap
private import semmle.code.java.dataflow.ExternalFlow
/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
abstract class LdapInjectionSink extends DataFlow::Node { }
@@ -28,70 +29,56 @@ class LdapInjectionAdditionalTaintStep extends Unit {
/** Default sink for LDAP injection vulnerabilities. */
private class DefaultLdapInjectionSink extends LdapInjectionSink {
DefaultLdapInjectionSink() {
exists(MethodAccess ma, Method m, int index |
ma.getMethod() = m and
ma.getArgument(index) = this.asExpr() and
ldapInjectionSinkMethod(m, index)
)
DefaultLdapInjectionSink() { sinkNode(this, "ldap") }
}
private class DefaultLdapInjectionSinkModel extends SinkModelCsv {
override predicate row(string row) {
row =
[
// jndi
"javax.naming.directory;DirContext;true;search;;;Argument[0..1];ldap",
// apache
"org.apache.directory.ldap.client.api;LdapConnection;true;search;;;Argument[0..2];ldap",
// UnboundID: search
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(ReadOnlySearchRequest);;Argument[0];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchRequest);;Argument[0];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchResultListener,String,SearchScope,DereferencePolicy,int,int,boolean,Filter,String[]);;Argument[0..7];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchResultListener,String,SearchScope,DereferencePolicy,int,int,boolean,String,String[]);;Argument[0..7];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchResultListener,String,SearchScope,Filter,String[]);;Argument[0..3];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchResultListener,String,SearchScope,String,String[]);;Argument[0..3];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(String,SearchScope,DereferencePolicy,int,int,boolean,Filter,String[]);;Argument[0..6];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(String,SearchScope,DereferencePolicy,int,int,boolean,String,String[]);;Argument[0..6];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(String,SearchScope,Filter,String[]);;Argument[0..2];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;search;(String,SearchScope,String,String[]);;Argument[0..2];ldap",
// UnboundID: searchForEntry
"com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(ReadOnlySearchRequest);;Argument[0];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(SearchRequest);;Argument[0];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(String,SearchScope,DereferencePolicy,int,boolean,Filter,String[]);;Argument[0..5];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(String,SearchScope,DereferencePolicy,int,boolean,String,String[]);;Argument[0..5];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(String,SearchScope,Filter,String[]);;Argument[0..2];ldap",
"com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(String,SearchScope,String,String[]);;Argument[0..2];ldap",
// UnboundID: asyncSearch
"com.unboundid.ldap.sdk;LDAPConnection;false;asyncSearch;;;Argument[0];ldap",
// Spring
"org.springframework.ldap.core;LdapTemplate;false;find;;;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;findOne;;;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;search;;;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;searchForContext;;;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;searchForObject;;;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;authenticate;(LdapQuery,String);;Argument[0];ldap",
"org.springframework.ldap.core;LdapTemplate;false;authenticate;(Name,String,String);;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;authenticate;(Name,String,String,AuthenticatedLdapEntryContextCallback);;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;authenticate;(Name,String,String,AuthenticatedLdapEntryContextCallback,AuthenticationErrorCallback);;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;authenticate;(Name,String,String,AuthenticationErrorCallback);;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;authenticate;(String,String,String);;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;authenticate;(String,String,String,AuthenticatedLdapEntryContextCallback);;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;authenticate;(String,String,String,AuthenticatedLdapEntryContextCallback,AuthenticationErrorCallback);;Argument[0..1];ldap",
"org.springframework.ldap.core;LdapTemplate;false;authenticate;(String,String,String,AuthenticationErrorCallback);;Argument[0..1];ldap"
]
}
}
/** Holds if the method parameter at `index` is susceptible to an LDAP injection attack. */
private predicate ldapInjectionSinkMethod(Method m, int index) {
jndiLdapInjectionSinkMethod(m, index) or
unboundIdLdapInjectionSinkMethod(m, index) or
springLdapInjectionSinkMethod(m, index) or
apacheLdapInjectionSinkMethod(m, index)
}
/** Holds if the JNDI method parameter at `index` is susceptible to an LDAP injection attack. */
private predicate jndiLdapInjectionSinkMethod(Method m, int index) {
m.getDeclaringType().getAnAncestor() instanceof TypeDirContext and
m.hasName("search") and
index in [0 .. 1]
}
/** Holds if the UnboundID method parameter at `index` is susceptible to an LDAP injection attack. */
private predicate unboundIdLdapInjectionSinkMethod(Method m, int index) {
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
m instanceof MethodUnboundIdLDAPConnectionSearch or
m instanceof MethodUnboundIdLDAPConnectionAsyncSearch or
m instanceof MethodUnboundIdLDAPConnectionSearchForEntry
)
}
/** Holds if the Spring method parameter at `index` is susceptible to an LDAP injection attack. */
private predicate springLdapInjectionSinkMethod(Method m, int index) {
// LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method
(
m instanceof MethodSpringLdapTemplateAuthenticate or
m instanceof MethodSpringLdapTemplateFind or
m instanceof MethodSpringLdapTemplateFindOne or
m instanceof MethodSpringLdapTemplateSearch or
m instanceof MethodSpringLdapTemplateSearchForContext or
m instanceof MethodSpringLdapTemplateSearchForObject
) and
(
// Parameter index is 1 (DN or query) or 2 (filter) if method is not authenticate
index in [0 .. 1] and
not m instanceof MethodSpringLdapTemplateAuthenticate
or
// But it's not the last parameter in case of authenticate method (last param is password)
index in [0 .. 1] and
index < m.getNumberOfParameters() - 1 and
m instanceof MethodSpringLdapTemplateAuthenticate
)
}
/** Holds if the Apache LDAP API method parameter at `index` is susceptible to an LDAP injection attack. */
private predicate apacheLdapInjectionSinkMethod(Method m, int index) {
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
m.getDeclaringType().getAnAncestor() instanceof TypeApacheLdapConnection and
m.hasName("search")
)
}
/** A sanitizer that clears the taint on (boxed) primitive types. */
private class DefaultLdapSanitizer extends LdapInjectionSanitizer {
DefaultLdapSanitizer() {

View File

@@ -1,48 +1,81 @@
edges
| XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | XsltInjection.java:31:5:31:59 | newTransformer(...) |
| XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | XsltInjection.java:36:5:36:74 | newTransformer(...) |
| XsltInjection.java:40:45:40:70 | param : String | XsltInjection.java:43:5:43:59 | newTransformer(...) |
| XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | XsltInjection.java:48:5:48:74 | newTransformer(...) |
| XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | XsltInjection.java:53:5:53:59 | newTransformer(...) |
| XsltInjection.java:30:27:30:67 | new StreamSource(...) : StreamSource | XsltInjection.java:31:5:31:59 | newTransformer(...) |
| XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | XsltInjection.java:30:27:30:67 | new StreamSource(...) : StreamSource |
| XsltInjection.java:35:27:35:90 | new StreamSource(...) : StreamSource | XsltInjection.java:36:5:36:74 | newTransformer(...) |
| XsltInjection.java:35:44:35:89 | new InputStreamReader(...) : InputStreamReader | XsltInjection.java:35:27:35:90 | new StreamSource(...) : StreamSource |
| XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | XsltInjection.java:35:44:35:89 | new InputStreamReader(...) : InputStreamReader |
| XsltInjection.java:40:45:40:70 | param : String | XsltInjection.java:42:61:42:64 | xslt : String |
| XsltInjection.java:42:27:42:66 | new StreamSource(...) : StreamSource | XsltInjection.java:43:5:43:59 | newTransformer(...) |
| XsltInjection.java:42:44:42:65 | new StringReader(...) : StringReader | XsltInjection.java:42:27:42:66 | new StreamSource(...) : StreamSource |
| XsltInjection.java:42:61:42:64 | xslt : String | XsltInjection.java:42:44:42:65 | new StringReader(...) : StringReader |
| XsltInjection.java:47:24:47:78 | new SAXSource(...) : SAXSource | XsltInjection.java:48:5:48:74 | newTransformer(...) |
| XsltInjection.java:47:38:47:77 | new InputSource(...) : InputSource | XsltInjection.java:47:24:47:78 | new SAXSource(...) : SAXSource |
| XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | XsltInjection.java:47:38:47:77 | new InputSource(...) : InputSource |
| XsltInjection.java:52:24:52:107 | new SAXSource(...) : SAXSource | XsltInjection.java:53:5:53:59 | newTransformer(...) |
| XsltInjection.java:52:44:52:106 | new InputSource(...) : InputSource | XsltInjection.java:52:24:52:107 | new SAXSource(...) : SAXSource |
| XsltInjection.java:52:60:52:105 | new InputStreamReader(...) : InputStreamReader | XsltInjection.java:52:44:52:106 | new InputSource(...) : InputSource |
| XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | XsltInjection.java:52:60:52:105 | new InputStreamReader(...) : InputStreamReader |
| XsltInjection.java:57:91:57:113 | getInputStream(...) : InputStream | XsltInjection.java:58:5:58:59 | newTransformer(...) |
| XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | XsltInjection.java:63:5:63:74 | newTransformer(...) |
| XsltInjection.java:62:98:62:143 | new InputStreamReader(...) : InputStreamReader | XsltInjection.java:63:5:63:74 | newTransformer(...) |
| XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | XsltInjection.java:62:98:62:143 | new InputStreamReader(...) : InputStreamReader |
| XsltInjection.java:67:102:67:124 | getInputStream(...) : InputStream | XsltInjection.java:68:5:68:59 | newTransformer(...) |
| XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | XsltInjection.java:76:5:76:34 | newTransformer(...) |
| XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | XsltInjection.java:83:5:83:34 | newTransformer(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:90:5:90:35 | load(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:91:5:91:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:92:5:92:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:93:5:93:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:94:5:94:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:95:5:95:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:96:5:96:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:97:5:97:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:98:5:98:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:99:5:99:37 | load30(...) |
| XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:108:5:108:46 | load(...) |
| XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:110:5:110:50 | load(...) |
| XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | XsltInjection.java:109:5:109:49 | load(...) |
| XsltInjection.java:72:27:72:67 | new StreamSource(...) : StreamSource | XsltInjection.java:76:5:76:34 | newTransformer(...) |
| XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | XsltInjection.java:72:27:72:67 | new StreamSource(...) : StreamSource |
| XsltInjection.java:80:27:80:67 | new StreamSource(...) : StreamSource | XsltInjection.java:83:5:83:34 | newTransformer(...) |
| XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | XsltInjection.java:80:27:80:67 | new StreamSource(...) : StreamSource |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:90:5:90:35 | load(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:91:5:91:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:92:5:92:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:93:5:93:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:94:5:94:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:95:5:95:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:96:5:96:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:97:5:97:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:98:5:98:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:99:5:99:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource |
| XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:104:23:104:27 | param : String |
| XsltInjection.java:104:15:104:28 | new URI(...) : URI | XsltInjection.java:108:5:108:46 | load(...) |
| XsltInjection.java:104:15:104:28 | new URI(...) : URI | XsltInjection.java:110:5:110:50 | load(...) |
| XsltInjection.java:104:23:104:27 | param : String | XsltInjection.java:104:15:104:28 | new URI(...) : URI |
| XsltInjection.java:105:27:105:67 | new StreamSource(...) : StreamSource | XsltInjection.java:109:5:109:49 | load(...) |
| XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | XsltInjection.java:105:27:105:67 | new StreamSource(...) : StreamSource |
nodes
| XsltInjection.java:30:27:30:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:31:5:31:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:35:27:35:90 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| XsltInjection.java:35:44:35:89 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
| XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:36:5:36:74 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:40:45:40:70 | param : String | semmle.label | param : String |
| XsltInjection.java:42:27:42:66 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| XsltInjection.java:42:44:42:65 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader |
| XsltInjection.java:42:61:42:64 | xslt : String | semmle.label | xslt : String |
| XsltInjection.java:43:5:43:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:47:24:47:78 | new SAXSource(...) : SAXSource | semmle.label | new SAXSource(...) : SAXSource |
| XsltInjection.java:47:38:47:77 | new InputSource(...) : InputSource | semmle.label | new InputSource(...) : InputSource |
| XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:48:5:48:74 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:52:24:52:107 | new SAXSource(...) : SAXSource | semmle.label | new SAXSource(...) : SAXSource |
| XsltInjection.java:52:44:52:106 | new InputSource(...) : InputSource | semmle.label | new InputSource(...) : InputSource |
| XsltInjection.java:52:60:52:105 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
| XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:53:5:53:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:57:91:57:113 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:58:5:58:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:62:98:62:143 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
| XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:63:5:63:74 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:67:102:67:124 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:68:5:68:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:72:27:72:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:76:5:76:34 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:80:27:80:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:83:5:83:34 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:90:5:90:35 | load(...) | semmle.label | load(...) |
| XsltInjection.java:91:5:91:37 | load30(...) | semmle.label | load30(...) |
@@ -55,6 +88,9 @@ nodes
| XsltInjection.java:98:5:98:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:99:5:99:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:103:36:103:61 | param : String | semmle.label | param : String |
| XsltInjection.java:104:15:104:28 | new URI(...) : URI | semmle.label | new URI(...) : URI |
| XsltInjection.java:104:23:104:27 | param : String | semmle.label | param : String |
| XsltInjection.java:105:27:105:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:108:5:108:46 | load(...) | semmle.label | load(...) |
| XsltInjection.java:109:5:109:49 | load(...) | semmle.label | load(...) |

View File

@@ -0,0 +1,39 @@
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyCodeSource;
import groovy.lang.GroovyObject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class GroovyClassLoaderTest extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String script = request.getParameter("script");
final GroovyClassLoader classLoader = new GroovyClassLoader();
Class groovy = classLoader.parseClass(script);
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
} catch (Exception e) {
// Ignore
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String script = request.getParameter("script");
final GroovyClassLoader classLoader = new GroovyClassLoader();
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
Class groovy = classLoader.parseClass(gcs);
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
} catch (Exception e) {
// Ignore
}
}
}

View File

@@ -0,0 +1,41 @@
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import groovy.util.Eval;
public class GroovyEvalTest extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.me(script);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.me("test", "result", script);
}
protected void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.x("result2", script);
}
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.xy("result3", "result4", script);
}
protected void doPatch(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.xyz("result3", "result4", "aaa", script);
}
}

View File

@@ -0,0 +1,73 @@
edges
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:22:29:22:51 | expression : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:23:31:23:40 | expression |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:30:44:30:66 | expression : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:31:27:31:36 | expression |
| GroovyClassLoaderTest.java:16:29:16:58 | getParameter(...) : String | GroovyClassLoaderTest.java:18:51:18:56 | script |
| GroovyClassLoaderTest.java:29:29:29:58 | getParameter(...) : String | GroovyClassLoaderTest.java:32:51:32:53 | gcs |
| GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | GroovyEvalTest.java:13:17:13:22 | script |
| GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | GroovyEvalTest.java:13:17:13:22 | script : String |
| GroovyEvalTest.java:13:17:13:22 | script : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:22:29:22:51 | expression : String |
| GroovyEvalTest.java:18:25:18:54 | getParameter(...) : String | GroovyEvalTest.java:19:35:19:40 | script |
| GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | GroovyEvalTest.java:25:27:25:32 | script |
| GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | GroovyEvalTest.java:25:27:25:32 | script : String |
| GroovyEvalTest.java:25:27:25:32 | script : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:30:44:30:66 | expression : String |
| GroovyEvalTest.java:31:25:31:54 | getParameter(...) : String | GroovyEvalTest.java:32:39:32:44 | script |
| GroovyEvalTest.java:37:25:37:54 | getParameter(...) : String | GroovyEvalTest.java:38:47:38:52 | script |
| GroovyShellTest.java:15:25:15:54 | getParameter(...) : String | GroovyShellTest.java:16:24:16:29 | script |
| GroovyShellTest.java:22:25:22:54 | getParameter(...) : String | GroovyShellTest.java:23:24:23:29 | script |
| GroovyShellTest.java:29:25:29:54 | getParameter(...) : String | GroovyShellTest.java:30:24:30:29 | script |
| GroovyShellTest.java:36:25:36:54 | getParameter(...) : String | GroovyShellTest.java:37:19:37:24 | script |
| GroovyShellTest.java:43:25:43:54 | getParameter(...) : String | GroovyShellTest.java:45:19:45:21 | gcs |
| GroovyShellTest.java:51:25:51:54 | getParameter(...) : String | GroovyShellTest.java:53:24:53:26 | gcs |
| GroovyShellTest.java:59:25:59:54 | getParameter(...) : String | GroovyShellTest.java:60:21:60:26 | script |
nodes
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:22:29:22:51 | expression : String | semmle.label | expression : String |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:23:31:23:40 | expression | semmle.label | expression |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:30:44:30:66 | expression : String | semmle.label | expression : String |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:31:27:31:36 | expression | semmle.label | expression |
| GroovyClassLoaderTest.java:16:29:16:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyClassLoaderTest.java:18:51:18:56 | script | semmle.label | script |
| GroovyClassLoaderTest.java:29:29:29:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyClassLoaderTest.java:32:51:32:53 | gcs | semmle.label | gcs |
| GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:13:17:13:22 | script | semmle.label | script |
| GroovyEvalTest.java:13:17:13:22 | script : String | semmle.label | script : String |
| GroovyEvalTest.java:18:25:18:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:19:35:19:40 | script | semmle.label | script |
| GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:25:27:25:32 | script | semmle.label | script |
| GroovyEvalTest.java:25:27:25:32 | script : String | semmle.label | script : String |
| GroovyEvalTest.java:31:25:31:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:32:39:32:44 | script | semmle.label | script |
| GroovyEvalTest.java:37:25:37:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:38:47:38:52 | script | semmle.label | script |
| GroovyShellTest.java:15:25:15:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:16:24:16:29 | script | semmle.label | script |
| GroovyShellTest.java:22:25:22:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:23:24:23:29 | script | semmle.label | script |
| GroovyShellTest.java:29:25:29:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:30:24:30:29 | script | semmle.label | script |
| GroovyShellTest.java:36:25:36:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:37:19:37:24 | script | semmle.label | script |
| GroovyShellTest.java:43:25:43:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:45:19:45:21 | gcs | semmle.label | gcs |
| GroovyShellTest.java:51:25:51:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:53:24:53:26 | gcs | semmle.label | gcs |
| GroovyShellTest.java:59:25:59:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:60:21:60:26 | script | semmle.label | script |
#select
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:23:31:23:40 | expression | GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:23:31:23:40 | expression | Groovy Injection from $@. | GroovyEvalTest.java:12:25:12:54 | getParameter(...) | this user input |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:31:27:31:36 | expression | GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:31:27:31:36 | expression | Groovy Injection from $@. | GroovyEvalTest.java:24:25:24:54 | getParameter(...) | this user input |
| GroovyClassLoaderTest.java:18:51:18:56 | script | GroovyClassLoaderTest.java:16:29:16:58 | getParameter(...) : String | GroovyClassLoaderTest.java:18:51:18:56 | script | Groovy Injection from $@. | GroovyClassLoaderTest.java:16:29:16:58 | getParameter(...) | this user input |
| GroovyClassLoaderTest.java:32:51:32:53 | gcs | GroovyClassLoaderTest.java:29:29:29:58 | getParameter(...) : String | GroovyClassLoaderTest.java:32:51:32:53 | gcs | Groovy Injection from $@. | GroovyClassLoaderTest.java:29:29:29:58 | getParameter(...) | this user input |
| GroovyEvalTest.java:13:17:13:22 | script | GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | GroovyEvalTest.java:13:17:13:22 | script | Groovy Injection from $@. | GroovyEvalTest.java:12:25:12:54 | getParameter(...) | this user input |
| GroovyEvalTest.java:19:35:19:40 | script | GroovyEvalTest.java:18:25:18:54 | getParameter(...) : String | GroovyEvalTest.java:19:35:19:40 | script | Groovy Injection from $@. | GroovyEvalTest.java:18:25:18:54 | getParameter(...) | this user input |
| GroovyEvalTest.java:25:27:25:32 | script | GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | GroovyEvalTest.java:25:27:25:32 | script | Groovy Injection from $@. | GroovyEvalTest.java:24:25:24:54 | getParameter(...) | this user input |
| GroovyEvalTest.java:32:39:32:44 | script | GroovyEvalTest.java:31:25:31:54 | getParameter(...) : String | GroovyEvalTest.java:32:39:32:44 | script | Groovy Injection from $@. | GroovyEvalTest.java:31:25:31:54 | getParameter(...) | this user input |
| GroovyEvalTest.java:38:47:38:52 | script | GroovyEvalTest.java:37:25:37:54 | getParameter(...) : String | GroovyEvalTest.java:38:47:38:52 | script | Groovy Injection from $@. | GroovyEvalTest.java:37:25:37:54 | getParameter(...) | this user input |
| GroovyShellTest.java:16:24:16:29 | script | GroovyShellTest.java:15:25:15:54 | getParameter(...) : String | GroovyShellTest.java:16:24:16:29 | script | Groovy Injection from $@. | GroovyShellTest.java:15:25:15:54 | getParameter(...) | this user input |
| GroovyShellTest.java:23:24:23:29 | script | GroovyShellTest.java:22:25:22:54 | getParameter(...) : String | GroovyShellTest.java:23:24:23:29 | script | Groovy Injection from $@. | GroovyShellTest.java:22:25:22:54 | getParameter(...) | this user input |
| GroovyShellTest.java:30:24:30:29 | script | GroovyShellTest.java:29:25:29:54 | getParameter(...) : String | GroovyShellTest.java:30:24:30:29 | script | Groovy Injection from $@. | GroovyShellTest.java:29:25:29:54 | getParameter(...) | this user input |
| GroovyShellTest.java:37:19:37:24 | script | GroovyShellTest.java:36:25:36:54 | getParameter(...) : String | GroovyShellTest.java:37:19:37:24 | script | Groovy Injection from $@. | GroovyShellTest.java:36:25:36:54 | getParameter(...) | this user input |
| GroovyShellTest.java:45:19:45:21 | gcs | GroovyShellTest.java:43:25:43:54 | getParameter(...) : String | GroovyShellTest.java:45:19:45:21 | gcs | Groovy Injection from $@. | GroovyShellTest.java:43:25:43:54 | getParameter(...) | this user input |
| GroovyShellTest.java:53:24:53:26 | gcs | GroovyShellTest.java:51:25:51:54 | getParameter(...) : String | GroovyShellTest.java:53:24:53:26 | gcs | Groovy Injection from $@. | GroovyShellTest.java:51:25:51:54 | getParameter(...) | this user input |
| GroovyShellTest.java:60:21:60:26 | script | GroovyShellTest.java:59:25:59:54 | getParameter(...) : String | GroovyShellTest.java:60:21:60:26 | script | Groovy Injection from $@. | GroovyShellTest.java:59:25:59:54 | getParameter(...) | this user input |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-094/GroovyInjection.ql

View File

@@ -0,0 +1,63 @@
import groovy.lang.GroovyCodeSource;
import groovy.lang.GroovyShell;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class GroovyShellTest extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script, "test");
}
protected void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script, "test", "test2");
}
protected void doOptions(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.run(script, "_", new String[]{});
}
protected void doHead(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
shell.run(gcs, new String[]{});
}
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
shell.evaluate(gcs);
}
protected void doPatch(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.parse(script);
}
}

View File

@@ -1,5 +1,6 @@
edges
| JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:25:31:25:40 | expression : String |
| JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:23:54:23:58 | bytes [post update] : byte[] |
| JakartaExpressionInjection.java:23:54:23:58 | bytes [post update] : byte[] | JakartaExpressionInjection.java:25:31:25:40 | expression : String |
| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:32:24:32:33 | expression : String |
| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:40:24:40:33 | expression : String |
| JakartaExpressionInjection.java:25:31:25:40 | expression : String | JakartaExpressionInjection.java:48:24:48:33 | expression : String |
@@ -18,6 +19,7 @@ edges
| JakartaExpressionInjection.java:95:24:95:33 | expression : String | JakartaExpressionInjection.java:99:13:99:13 | e |
nodes
| JakartaExpressionInjection.java:23:25:23:47 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| JakartaExpressionInjection.java:23:54:23:58 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| JakartaExpressionInjection.java:25:31:25:40 | expression : String | semmle.label | expression : String |
| JakartaExpressionInjection.java:32:24:32:33 | expression : String | semmle.label | expression : String |
| JakartaExpressionInjection.java:34:28:34:37 | expression | semmle.label | expression |

View File

@@ -8,7 +8,8 @@ edges
| Jexl2Injection.java:54:73:54:87 | jexlExpr : String | Jexl2Injection.java:57:9:57:35 | parse(...) |
| Jexl2Injection.java:60:72:60:86 | jexlExpr : String | Jexl2Injection.java:63:9:63:35 | parse(...) |
| Jexl2Injection.java:66:73:66:87 | jexlExpr : String | Jexl2Injection.java:69:9:69:44 | createTemplate(...) |
| Jexl2Injection.java:76:25:76:47 | getInputStream(...) : InputStream | Jexl2Injection.java:78:31:78:38 | jexlExpr : String |
| Jexl2Injection.java:76:25:76:47 | getInputStream(...) : InputStream | Jexl2Injection.java:76:54:76:58 | bytes [post update] : byte[] |
| Jexl2Injection.java:76:54:76:58 | bytes [post update] : byte[] | Jexl2Injection.java:78:31:78:38 | jexlExpr : String |
| Jexl2Injection.java:78:31:78:38 | jexlExpr : String | Jexl2Injection.java:86:24:86:56 | jexlExpr : String |
| Jexl2Injection.java:78:31:78:38 | jexlExpr : String | Jexl2Injection.java:90:24:90:68 | jexlExpr : String |
| Jexl2Injection.java:78:31:78:38 | jexlExpr : String | Jexl2Injection.java:94:24:94:52 | jexlExpr : String |
@@ -46,7 +47,8 @@ edges
| Jexl3Injection.java:66:73:66:87 | jexlExpr : String | Jexl3Injection.java:69:9:69:39 | createExpression(...) |
| Jexl3Injection.java:72:72:72:86 | jexlExpr : String | Jexl3Injection.java:75:9:75:37 | createTemplate(...) |
| Jexl3Injection.java:78:54:78:68 | jexlExpr : String | Jexl3Injection.java:84:13:84:13 | e |
| Jexl3Injection.java:94:25:94:47 | getInputStream(...) : InputStream | Jexl3Injection.java:96:31:96:38 | jexlExpr : String |
| Jexl3Injection.java:94:25:94:47 | getInputStream(...) : InputStream | Jexl3Injection.java:94:54:94:58 | bytes [post update] : byte[] |
| Jexl3Injection.java:94:54:94:58 | bytes [post update] : byte[] | Jexl3Injection.java:96:31:96:38 | jexlExpr : String |
| Jexl3Injection.java:96:31:96:38 | jexlExpr : String | Jexl3Injection.java:104:24:104:56 | jexlExpr : String |
| Jexl3Injection.java:96:31:96:38 | jexlExpr : String | Jexl3Injection.java:108:24:108:68 | jexlExpr : String |
| Jexl3Injection.java:96:31:96:38 | jexlExpr : String | Jexl3Injection.java:112:24:112:52 | jexlExpr : String |
@@ -103,6 +105,7 @@ nodes
| Jexl2Injection.java:66:73:66:87 | jexlExpr : String | semmle.label | jexlExpr : String |
| Jexl2Injection.java:69:9:69:44 | createTemplate(...) | semmle.label | createTemplate(...) |
| Jexl2Injection.java:76:25:76:47 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| Jexl2Injection.java:76:54:76:58 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| Jexl2Injection.java:78:31:78:38 | jexlExpr : String | semmle.label | jexlExpr : String |
| Jexl2Injection.java:86:24:86:56 | jexlExpr : String | semmle.label | jexlExpr : String |
| Jexl2Injection.java:86:24:86:56 | jexlExpr : String | semmle.label | jexlExpr : String |
@@ -143,6 +146,7 @@ nodes
| Jexl3Injection.java:78:54:78:68 | jexlExpr : String | semmle.label | jexlExpr : String |
| Jexl3Injection.java:84:13:84:13 | e | semmle.label | e |
| Jexl3Injection.java:94:25:94:47 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| Jexl3Injection.java:94:54:94:58 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| Jexl3Injection.java:96:31:96:38 | jexlExpr : String | semmle.label | jexlExpr : String |
| Jexl3Injection.java:104:24:104:56 | jexlExpr : String | semmle.label | jexlExpr : String |
| Jexl3Injection.java:104:24:104:56 | jexlExpr : String | semmle.label | jexlExpr : String |

View File

@@ -10,7 +10,9 @@ edges
| MvelInjection.java:77:40:77:51 | read(...) : String | MvelInjection.java:77:7:77:52 | compileTemplate(...) |
| MvelInjection.java:81:54:81:65 | read(...) : String | MvelInjection.java:82:29:82:46 | compile(...) |
| MvelInjection.java:86:58:86:69 | read(...) : String | MvelInjection.java:88:32:88:41 | expression |
| MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:95:14:95:36 | new String(...) : String |
| MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:94:15:94:16 | is : InputStream |
| MvelInjection.java:94:15:94:16 | is : InputStream | MvelInjection.java:94:23:94:27 | bytes [post update] : byte[] |
| MvelInjection.java:94:23:94:27 | bytes [post update] : byte[] | MvelInjection.java:95:14:95:36 | new String(...) : String |
| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:25:15:25:26 | read(...) |
| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:29:54:29:65 | read(...) : String |
| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:34:58:34:69 | read(...) : String |
@@ -46,6 +48,8 @@ nodes
| MvelInjection.java:86:58:86:69 | read(...) : String | semmle.label | read(...) : String |
| MvelInjection.java:88:32:88:41 | expression | semmle.label | expression |
| MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| MvelInjection.java:94:15:94:16 | is : InputStream | semmle.label | is : InputStream |
| MvelInjection.java:94:23:94:27 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| MvelInjection.java:95:14:95:36 | new String(...) : String | semmle.label | new String(...) : String |
#select
| MvelInjection.java:25:15:25:26 | read(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:25:15:25:26 | read(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input |

View File

@@ -1,22 +1,46 @@
edges
| SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | SpelInjection.java:23:5:23:14 | expression |
| SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | SpelInjection.java:34:5:34:14 | expression |
| SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | SpelInjection.java:48:5:48:14 | expression |
| SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | SpelInjection.java:59:5:59:14 | expression |
| SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | SpelInjection.java:70:5:70:14 | expression |
| SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | SpelInjection.java:83:5:83:14 | expression |
| SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | SpelInjection.java:18:13:18:14 | in : InputStream |
| SpelInjection.java:18:13:18:14 | in : InputStream | SpelInjection.java:18:21:18:25 | bytes [post update] : byte[] |
| SpelInjection.java:18:21:18:25 | bytes [post update] : byte[] | SpelInjection.java:23:5:23:14 | expression |
| SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | SpelInjection.java:30:13:30:14 | in : InputStream |
| SpelInjection.java:30:13:30:14 | in : InputStream | SpelInjection.java:30:21:30:25 | bytes [post update] : byte[] |
| SpelInjection.java:30:21:30:25 | bytes [post update] : byte[] | SpelInjection.java:34:5:34:14 | expression |
| SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | SpelInjection.java:41:13:41:14 | in : InputStream |
| SpelInjection.java:41:13:41:14 | in : InputStream | SpelInjection.java:41:21:41:25 | bytes [post update] : byte[] |
| SpelInjection.java:41:21:41:25 | bytes [post update] : byte[] | SpelInjection.java:48:5:48:14 | expression |
| SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | SpelInjection.java:55:13:55:14 | in : InputStream |
| SpelInjection.java:55:13:55:14 | in : InputStream | SpelInjection.java:55:21:55:25 | bytes [post update] : byte[] |
| SpelInjection.java:55:21:55:25 | bytes [post update] : byte[] | SpelInjection.java:59:5:59:14 | expression |
| SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | SpelInjection.java:66:13:66:14 | in : InputStream |
| SpelInjection.java:66:13:66:14 | in : InputStream | SpelInjection.java:66:21:66:25 | bytes [post update] : byte[] |
| SpelInjection.java:66:21:66:25 | bytes [post update] : byte[] | SpelInjection.java:70:5:70:14 | expression |
| SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | SpelInjection.java:77:13:77:14 | in : InputStream |
| SpelInjection.java:77:13:77:14 | in : InputStream | SpelInjection.java:77:21:77:25 | bytes [post update] : byte[] |
| SpelInjection.java:77:21:77:25 | bytes [post update] : byte[] | SpelInjection.java:83:5:83:14 | expression |
nodes
| SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| SpelInjection.java:18:13:18:14 | in : InputStream | semmle.label | in : InputStream |
| SpelInjection.java:18:21:18:25 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| SpelInjection.java:23:5:23:14 | expression | semmle.label | expression |
| SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| SpelInjection.java:30:13:30:14 | in : InputStream | semmle.label | in : InputStream |
| SpelInjection.java:30:21:30:25 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| SpelInjection.java:34:5:34:14 | expression | semmle.label | expression |
| SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| SpelInjection.java:41:13:41:14 | in : InputStream | semmle.label | in : InputStream |
| SpelInjection.java:41:21:41:25 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| SpelInjection.java:48:5:48:14 | expression | semmle.label | expression |
| SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| SpelInjection.java:55:13:55:14 | in : InputStream | semmle.label | in : InputStream |
| SpelInjection.java:55:21:55:25 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| SpelInjection.java:59:5:59:14 | expression | semmle.label | expression |
| SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| SpelInjection.java:66:13:66:14 | in : InputStream | semmle.label | in : InputStream |
| SpelInjection.java:66:21:66:25 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| SpelInjection.java:70:5:70:14 | expression | semmle.label | expression |
| SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| SpelInjection.java:77:13:77:14 | in : InputStream | semmle.label | in : InputStream |
| SpelInjection.java:77:21:77:25 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| SpelInjection.java:83:5:83:14 | expression | semmle.label | expression |
#select
| SpelInjection.java:23:5:23:14 | expression | SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | SpelInjection.java:23:5:23:14 | expression | SpEL injection from $@. | SpelInjection.java:15:22:15:44 | getInputStream(...) | this user input |

View File

@@ -1 +1,2 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../../stubs/servlet-api-2.4

View File

@@ -1,5 +1,8 @@
edges
| SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String |
| SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie |
| SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie |
| SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... |
| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... |
| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) |
@@ -7,11 +10,16 @@ edges
| SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString |
| SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString |
| SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString |
| SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String |
| SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie |
| SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie |
| SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie |
nodes
| SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | semmle.label | "jwt_token" : String |
| SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | semmle.label | tokenCookieStr : String |
| SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | semmle.label | jwtCookie |
| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | semmle.label | "token=" : String |
| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | semmle.label | ... + ... : String |
@@ -25,6 +33,8 @@ nodes
| SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | semmle.label | ... + ... : String |
| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | semmle.label | secString |
| SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | semmle.label | "Presto-UI-Token" : String |
| SensitiveCookieNotHttpOnly.java:89:25:89:57 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:89:36:89:51 | PRESTO_UI_COOKIE : String | semmle.label | PRESTO_UI_COOKIE : String |
| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | semmle.label | cookie : Cookie |
| SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | semmle.label | createAuthenticationCookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | semmle.label | cookie |

View File

@@ -1,8 +1,14 @@
edges
| InsecureBasicAuth.java:20:39:20:52 | ... + ... : String | InsecureBasicAuth.java:28:3:28:6 | post |
| InsecureBasicAuth.java:35:19:35:64 | "http://www.example.com:8000/payment/retrieve" : String | InsecureBasicAuth.java:38:3:38:5 | get |
| InsecureBasicAuth.java:45:19:45:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:46:50:46:55 | uriStr : String |
| InsecureBasicAuth.java:45:19:45:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:54:3:54:6 | post |
| InsecureBasicAuth.java:46:39:46:56 | create(...) : URI | InsecureBasicAuth.java:54:3:54:6 | post |
| InsecureBasicAuth.java:46:50:46:55 | uriStr : String | InsecureBasicAuth.java:46:39:46:56 | create(...) : URI |
| InsecureBasicAuth.java:61:19:61:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:62:21:62:26 | uriStr : String |
| InsecureBasicAuth.java:61:19:61:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:71:3:71:6 | post |
| InsecureBasicAuth.java:62:13:62:27 | new URI(...) : URI | InsecureBasicAuth.java:71:3:71:6 | post |
| InsecureBasicAuth.java:62:21:62:26 | uriStr : String | InsecureBasicAuth.java:62:13:62:27 | new URI(...) : URI |
| InsecureBasicAuth.java:78:47:78:52 | "http" : String | InsecureBasicAuth.java:86:3:86:6 | post |
| InsecureBasicAuth.java:93:19:93:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:102:3:102:6 | post |
| InsecureBasicAuth.java:109:19:109:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:119:3:119:6 | post |
@@ -16,8 +22,12 @@ nodes
| InsecureBasicAuth.java:35:19:35:64 | "http://www.example.com:8000/payment/retrieve" : String | semmle.label | "http://www.example.com:8000/payment/retrieve" : String |
| InsecureBasicAuth.java:38:3:38:5 | get | semmle.label | get |
| InsecureBasicAuth.java:45:19:45:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
| InsecureBasicAuth.java:46:39:46:56 | create(...) : URI | semmle.label | create(...) : URI |
| InsecureBasicAuth.java:46:50:46:55 | uriStr : String | semmle.label | uriStr : String |
| InsecureBasicAuth.java:54:3:54:6 | post | semmle.label | post |
| InsecureBasicAuth.java:61:19:61:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
| InsecureBasicAuth.java:62:13:62:27 | new URI(...) : URI | semmle.label | new URI(...) : URI |
| InsecureBasicAuth.java:62:21:62:26 | uriStr : String | semmle.label | uriStr : String |
| InsecureBasicAuth.java:71:3:71:6 | post | semmle.label | post |
| InsecureBasicAuth.java:78:47:78:52 | "http" : String | semmle.label | "http" : String |
| InsecureBasicAuth.java:86:3:86:6 | post | semmle.label | post |

View File

@@ -5,10 +5,19 @@ edges
| XQueryInjection.java:86:33:86:60 | nameStr : String | XQueryInjection.java:92:53:92:57 | query |
| XQueryInjection.java:100:28:100:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:104:35:104:38 | xqpe |
| XQueryInjection.java:112:28:112:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:116:53:116:56 | name |
| XQueryInjection.java:124:28:124:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:129:35:129:38 | xqpe |
| XQueryInjection.java:137:28:137:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:142:53:142:54 | br |
| XQueryInjection.java:124:28:124:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:125:70:125:73 | name : ServletInputStream |
| XQueryInjection.java:125:29:125:75 | new BufferedReader(...) : BufferedReader | XQueryInjection.java:129:35:129:38 | xqpe |
| XQueryInjection.java:125:48:125:74 | new InputStreamReader(...) : InputStreamReader | XQueryInjection.java:125:29:125:75 | new BufferedReader(...) : BufferedReader |
| XQueryInjection.java:125:70:125:73 | name : ServletInputStream | XQueryInjection.java:125:48:125:74 | new InputStreamReader(...) : InputStreamReader |
| XQueryInjection.java:137:28:137:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:138:70:138:73 | name : ServletInputStream |
| XQueryInjection.java:138:29:138:75 | new BufferedReader(...) : BufferedReader | XQueryInjection.java:142:53:142:54 | br |
| XQueryInjection.java:138:48:138:74 | new InputStreamReader(...) : InputStreamReader | XQueryInjection.java:138:29:138:75 | new BufferedReader(...) : BufferedReader |
| XQueryInjection.java:138:70:138:73 | name : ServletInputStream | XQueryInjection.java:138:48:138:74 | new InputStreamReader(...) : InputStreamReader |
| XQueryInjection.java:150:23:150:50 | getParameter(...) : String | XQueryInjection.java:155:29:155:32 | name |
| XQueryInjection.java:157:26:157:49 | getInputStream(...) : ServletInputStream | XQueryInjection.java:159:29:159:30 | br |
| XQueryInjection.java:157:26:157:49 | getInputStream(...) : ServletInputStream | XQueryInjection.java:158:70:158:71 | is : ServletInputStream |
| XQueryInjection.java:158:29:158:73 | new BufferedReader(...) : BufferedReader | XQueryInjection.java:159:29:159:30 | br |
| XQueryInjection.java:158:48:158:72 | new InputStreamReader(...) : InputStreamReader | XQueryInjection.java:158:29:158:73 | new BufferedReader(...) : BufferedReader |
| XQueryInjection.java:158:70:158:71 | is : ServletInputStream | XQueryInjection.java:158:48:158:72 | new InputStreamReader(...) : InputStreamReader |
nodes
| XQueryInjection.java:45:23:45:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| XQueryInjection.java:51:35:51:38 | xqpe | semmle.label | xqpe |
@@ -23,12 +32,21 @@ nodes
| XQueryInjection.java:112:28:112:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream |
| XQueryInjection.java:116:53:116:56 | name | semmle.label | name |
| XQueryInjection.java:124:28:124:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream |
| XQueryInjection.java:125:29:125:75 | new BufferedReader(...) : BufferedReader | semmle.label | new BufferedReader(...) : BufferedReader |
| XQueryInjection.java:125:48:125:74 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
| XQueryInjection.java:125:70:125:73 | name : ServletInputStream | semmle.label | name : ServletInputStream |
| XQueryInjection.java:129:35:129:38 | xqpe | semmle.label | xqpe |
| XQueryInjection.java:137:28:137:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream |
| XQueryInjection.java:138:29:138:75 | new BufferedReader(...) : BufferedReader | semmle.label | new BufferedReader(...) : BufferedReader |
| XQueryInjection.java:138:48:138:74 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
| XQueryInjection.java:138:70:138:73 | name : ServletInputStream | semmle.label | name : ServletInputStream |
| XQueryInjection.java:142:53:142:54 | br | semmle.label | br |
| XQueryInjection.java:150:23:150:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| XQueryInjection.java:155:29:155:32 | name | semmle.label | name |
| XQueryInjection.java:157:26:157:49 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream |
| XQueryInjection.java:158:29:158:73 | new BufferedReader(...) : BufferedReader | semmle.label | new BufferedReader(...) : BufferedReader |
| XQueryInjection.java:158:48:158:72 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
| XQueryInjection.java:158:70:158:71 | is : ServletInputStream | semmle.label | is : ServletInputStream |
| XQueryInjection.java:159:29:159:30 | br | semmle.label | br |
#select
| XQueryInjection.java:51:35:51:38 | xqpe | XQueryInjection.java:45:23:45:50 | getParameter(...) : String | XQueryInjection.java:51:35:51:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:45:23:45:50 | getParameter(...) | this user input |

View File

@@ -1,5 +1,6 @@
edges
| JaxWsSSRF.java:21:22:21:48 | getParameter(...) : String | JaxWsSSRF.java:22:23:22:25 | url |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:25:31:25:34 | sink : String |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:55:32:55:35 | url1 |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:58:32:58:35 | url1 |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:59:30:59:33 | url1 |
@@ -7,6 +8,12 @@ edges
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:64:59:64:61 | uri |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:67:43:67:45 | uri |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:69:29:69:32 | uri2 |
| RequestForgery2.java:25:23:25:35 | new URI(...) : URI | RequestForgery2.java:64:59:64:61 | uri |
| RequestForgery2.java:25:23:25:35 | new URI(...) : URI | RequestForgery2.java:67:43:67:45 | uri |
| RequestForgery2.java:25:31:25:34 | sink : String | RequestForgery2.java:25:23:25:35 | new URI(...) : URI |
| RequestForgery.java:19:23:19:58 | new URI(...) : URI | RequestForgery.java:22:52:22:54 | uri |
| RequestForgery.java:19:23:19:58 | new URI(...) : URI | RequestForgery.java:27:57:27:59 | uri |
| RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:19:23:19:58 | new URI(...) : URI |
| RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:22:52:22:54 | uri |
| RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:27:57:27:59 | uri |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:32:47:32:67 | ... + ... |
@@ -15,13 +22,17 @@ edges
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:45:47:45:60 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:54:59:54:72 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:58:74:58:96 | new URI(...) |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:58:82:58:95 | fooResourceUrl : String |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:62:57:62:70 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:66:48:66:61 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:69:30:69:43 | fooResourceUrl |
| SpringSSRF.java:58:82:58:95 | fooResourceUrl : String | SpringSSRF.java:58:74:58:96 | new URI(...) |
nodes
| JaxWsSSRF.java:21:22:21:48 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| JaxWsSSRF.java:22:23:22:25 | url | semmle.label | url |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RequestForgery2.java:25:23:25:35 | new URI(...) : URI | semmle.label | new URI(...) : URI |
| RequestForgery2.java:25:31:25:34 | sink : String | semmle.label | sink : String |
| RequestForgery2.java:55:32:55:35 | url1 | semmle.label | url1 |
| RequestForgery2.java:58:32:58:35 | url1 | semmle.label | url1 |
| RequestForgery2.java:59:30:59:33 | url1 | semmle.label | url1 |
@@ -29,6 +40,7 @@ nodes
| RequestForgery2.java:64:59:64:61 | uri | semmle.label | uri |
| RequestForgery2.java:67:43:67:45 | uri | semmle.label | uri |
| RequestForgery2.java:69:29:69:32 | uri2 | semmle.label | uri2 |
| RequestForgery.java:19:23:19:58 | new URI(...) : URI | semmle.label | new URI(...) : URI |
| RequestForgery.java:19:31:19:57 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RequestForgery.java:22:52:22:54 | uri | semmle.label | uri |
| RequestForgery.java:27:57:27:59 | uri | semmle.label | uri |
@@ -39,6 +51,7 @@ nodes
| SpringSSRF.java:45:47:45:60 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:54:59:54:72 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:58:74:58:96 | new URI(...) | semmle.label | new URI(...) |
| SpringSSRF.java:58:82:58:95 | fooResourceUrl : String | semmle.label | fooResourceUrl : String |
| SpringSSRF.java:62:57:62:70 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:66:48:66:61 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:69:30:69:43 | fooResourceUrl | semmle.label | fooResourceUrl |

View File

@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 groovy.lang;
public class GroovyClassLoader {
public GroovyClassLoader() {
}
public Class parseClass(String text) {
return null;
}
public Class parseClass(GroovyCodeSource gcs) {
return null;
}
}

View File

@@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 groovy.lang;
public class GroovyCodeSource {
public GroovyCodeSource(String script, String param1, String param2) {}
}

View File

@@ -0,0 +1,21 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 groovy.lang;
public interface GroovyObject {}

View File

@@ -0,0 +1,66 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 groovy.lang;
import java.util.*;
public class GroovyShell {
public GroovyShell() {}
public Object evaluate(GroovyCodeSource codeSource) {
return null;
}
public Object evaluate(String scriptText) {
return null;
}
public Object evaluate(String scriptText, String fileName) {
return null;
}
public Object evaluate(String scriptText, final String fileName, final String codeBase) {
return null;
}
public Object run(String scriptText, String fileName, List<String> list) {
return null;
}
public Object run(String scriptText, String fileName, String[] args) {
return null;
}
public Object run(GroovyCodeSource source, List<String> args) {
return null;
}
public Object run(GroovyCodeSource source, String[] args) {
return null;
}
public Script parse(String scriptText) {
return null;
}
public Script parse(final String scriptText, final String fileName) {
return null;
}
}

View File

@@ -0,0 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 groovy.lang;
public abstract class Script {
}

View File

@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 groovy.util;
public class Eval {
public static Object me(final String expression) {
return me(null, null, expression);
}
public static Object me(final String symbol, final Object object, final String expression) {
return null;
}
public static Object x(final Object x, final String expression) {
return me("x", x, expression);
}
public static Object xy(final Object x, final Object y, final String expression) {
return null;
}
public static Object xyz(final Object x, final Object y, final Object z, final String expression) {
return null;
}
}

View File

@@ -1,10 +1,10 @@
invalidModelRow
#select
| C.java:6:16:6:19 | arg1 | C.java:6:5:6:20 | stepArgRes(...) | qltest |
| C.java:10:16:10:21 | argIn1 | C.java:10:24:10:30 | argOut1 [post update] | qltest |
| C.java:13:16:13:21 | argIn2 | C.java:13:24:13:30 | argOut2 [post update] | qltest |
| C.java:16:17:16:20 | arg2 | C.java:16:5:16:21 | this <.method> [post update] | qltest |
| C.java:18:22:18:25 | arg3 | C.java:18:5:18:8 | this [post update] | qltest |
| C.java:20:5:20:8 | this | C.java:20:5:20:22 | stepQualRes(...) | qltest |
| C.java:21:5:21:17 | this <.method> | C.java:21:5:21:17 | stepQualRes(...) | qltest |
| C.java:24:5:24:23 | this <.method> | C.java:24:17:24:22 | argOut [post update] | qltest |
| C.java:6:16:6:19 | arg1 | C.java:6:5:6:20 | stepArgRes(...) |
| C.java:10:16:10:21 | argIn1 | C.java:10:24:10:30 | argOut1 [post update] |
| C.java:13:16:13:21 | argIn2 | C.java:13:24:13:30 | argOut2 [post update] |
| C.java:16:17:16:20 | arg2 | C.java:16:5:16:21 | this <.method> [post update] |
| C.java:18:22:18:25 | arg3 | C.java:18:5:18:8 | this [post update] |
| C.java:20:5:20:8 | this | C.java:20:5:20:22 | stepQualRes(...) |
| C.java:21:5:21:17 | this <.method> | C.java:21:5:21:17 | stepQualRes(...) |
| C.java:24:5:24:23 | this <.method> | C.java:24:17:24:22 | argOut [post update] |

View File

@@ -1,6 +1,7 @@
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import CsvValidation
class SummaryModelTest extends SummaryModelCsv {
@@ -8,15 +9,15 @@ class SummaryModelTest extends SummaryModelCsv {
row =
[
//"package;type;overrides;name;signature;ext;inputspec;outputspec;kind",
"my.qltest;C;false;stepArgRes;(Object);;Argument[0];ReturnValue;qltest",
"my.qltest;C;false;stepArgArg;(Object,Object);;Argument[0];Argument[1];qltest",
"my.qltest;C;false;stepArgQual;(Object);;Argument[0];Argument[-1];qltest",
"my.qltest;C;false;stepQualRes;();;Argument[-1];ReturnValue;qltest",
"my.qltest;C;false;stepQualArg;(Object);;Argument[-1];Argument[0];qltest"
"my.qltest;C;false;stepArgRes;(Object);;Argument[0];ReturnValue;taint",
"my.qltest;C;false;stepArgArg;(Object,Object);;Argument[0];Argument[1];taint",
"my.qltest;C;false;stepArgQual;(Object);;Argument[0];Argument[-1];taint",
"my.qltest;C;false;stepQualRes;();;Argument[-1];ReturnValue;taint",
"my.qltest;C;false;stepQualArg;(Object);;Argument[-1];Argument[0];taint"
]
}
}
from DataFlow::Node node1, DataFlow::Node node2, string kind
where summaryStep(node1, node2, kind)
select node1, node2, kind
from DataFlow::Node node1, DataFlow::Node node2
where FlowSummaryImpl::Private::Steps::summaryThroughStep(node1, node2, false)
select node1, node2

View File

@@ -1,8 +1,12 @@
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.internal.TaintTrackingUtil
import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
from DataFlow::Node src, DataFlow::Node sink
where
localAdditionalTaintStep(src, sink) and
src.getLocation().getFile().getExtension() = "java"
(
localAdditionalTaintStep(src, sink) or
FlowSummaryImpl::Private::Steps::summaryThroughStep(src, sink, false)
) and
not FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
select src, sink

View File

@@ -1 +1 @@
//semmle-extractor-options: --javac-args --enable-preview -source 15 -target 15
//semmle-extractor-options: --javac-args -source 16 -target 16

View File

@@ -1 +0,0 @@
//semmle-extractor-options: --javac-args --enable-preview -source 15 -target 15

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