Compare commits

...

224 Commits

Author SHA1 Message Date
Geoffrey White
f2a4fbc522 Update query-metadata-style-guide.md
Added a bit about the @security-severity tag.
2021-07-29 17:41:58 +01:00
Jonas Jensen
768e5190a1 Merge pull request #4080 from geoffw0/split
C++: Split test file stl.cpp
2020-08-14 15:59:46 +02:00
Geoffrey White
89c2b6dc4b Merge remote-tracking branch 'upstream/master' into split 2020-08-14 14:03:34 +01:00
CodeQL CI
e9a36b2524 Merge pull request #4062 from tausbn/python-fix-unknown-import-star
Approved by yoff
2020-08-14 13:17:45 +01:00
Taus
8cbd4974ae Merge pull request #3981 from yoff/SharedDataflow_Classes
Python: Dataflow, test magic methods
2020-08-14 12:45:55 +02:00
Jonas Jensen
e01e702f46 Merge pull request #4060 from bgianfo/patch-1
C++: Detect GoogleTest tests cases in FNumberOfTests.ql
2020-08-14 12:42:12 +02:00
Rasmus Lerchedahl Petersen
9556937840 Python: address review comments 2020-08-14 11:29:58 +02:00
yoff
8d49ad7325 Update python/ql/test/experimental/dataflow/coverage/datamodel.py
Co-authored-by: Taus <tausbn@github.com>
2020-08-14 10:53:37 +02:00
yoff
4b336e9b01 Update python/ql/test/experimental/dataflow/coverage/classes.py
Co-authored-by: Taus <tausbn@github.com>
2020-08-14 10:53:10 +02:00
CodeQL CI
82f9826966 Merge pull request #4044 from aschackmull/java/xsssink-printwriter-format
Approved by aibaars
2020-08-14 08:34:48 +01:00
Robert Marsh
ed06604b46 Merge pull request #4045 from geoffw0/plus
C++: Model more of std::string in models.
2020-08-13 16:59:47 -04:00
Brian Gianforcaro
a6bcbe7974 C++: Detect GoogleTest tests cases in FNumberOfTests.ql
Co-authored-by: Jonas Jensen <jbj@github.com>
2020-08-13 12:06:00 -07:00
Geoffrey White
498b350add Merge remote-tracking branch 'upstream/master' into plus 2020-08-13 18:21:28 +01:00
Geoffrey White
a839f1fae5 C++: Split off stringstream.cpp. 2020-08-13 18:17:24 +01:00
Geoffrey White
49d2f66ddb C++: Tidy up sources and sinks. 2020-08-13 18:08:58 +01:00
Geoffrey White
f343eb9143 C++: Split stl.cpp into string.cpp and vector.cpp. 2020-08-13 18:04:46 +01:00
Geoffrey White
5d7f771933 C++: Split off stl.h from stl.cpp. 2020-08-13 18:04:45 +01:00
Robert Marsh
de87f8fc42 Merge pull request #4057 from geoffw0/sal
C++: SAL.qll QLDoc and cleanup
2020-08-13 12:33:52 -04:00
Geoffrey White
93f95b1c22 Merge pull request #4053 from jbj/SimpleRangeAnalysis-mul
C++: SimpleRangeAnalysis: unsigned multiplication
2020-08-13 16:59:31 +01:00
Anders Schack-Mulligen
ecbbcc2f61 Merge pull request #4066 from Marcono1234/marcono1234/simplify-VarAccess-isLValue
[Java] Simplify VarAccess.isLValue()
2020-08-13 16:40:28 +02:00
Geoffrey White
7349333006 C++: Taint through char append. 2020-08-13 15:13:47 +01:00
Geoffrey White
3c0e7a709f C++: Add a test of append with CharT. 2020-08-13 14:52:34 +01:00
Geoffrey White
732a8fa4c9 C++: Add another member function. 2020-08-13 14:52:34 +01:00
CodeQL CI
6c60589dbd Merge pull request #4063 from erik-krogh/noJsMsg
Approved by esbena
2020-08-13 14:02:18 +01:00
Anders Schack-Mulligen
3469ad7ca6 Merge pull request #3600 from luchua-bc/java-sensitive-log4j2-logging
Add Log4J 2 and a new search string secret
2020-08-13 13:35:52 +02:00
Marcono1234
cca2d9d825 Simplify VarAccess.isLValue() 2020-08-13 13:12:57 +02:00
Erik Krogh Kristensen
2c7bb8c51f adjust error message when files have been found while extracting 2020-08-13 11:18:27 +02:00
Taus Brock-Nannestad
a1a1218f95 Python: Ignore from foo import * when foo is absent. 2020-08-13 10:50:28 +02:00
Taus Brock-Nannestad
dc5c0f8e7a Python: Add test case for missing modules 2020-08-13 10:49:11 +02:00
Geoffrey White
f5abf74e0f Update cpp/ql/src/Microsoft/SAL.qll
Co-authored-by: Robert Marsh <rdmarsh2@gmail.com>
2020-08-13 09:05:22 +01:00
Anders Schack-Mulligen
8891ae70b6 Merge pull request #3938 from lcartey/java/untrusted-data-to-external-api
Java: Untrusted data used in external APIs
2020-08-13 09:53:57 +02:00
Jonas Jensen
5e5a112c36 C++: Change note 2020-08-13 08:37:13 +02:00
Geoffrey White
2655616a0a C++: Autoformat. 2020-08-12 16:59:15 +01:00
Geoffrey White
9719da8643 C++: Move a class that looks like it's intended to be public (and is used outside of the library) above the 'Implementation details' threshold. 2020-08-12 16:58:50 +01:00
Geoffrey White
d444778535 C++: Make a few things in SAL.qll private where it looks like that was intended (and they're not used outside the file). 2020-08-12 16:57:43 +01:00
Geoffrey White
aa6cb51bba C++: QLDoc SAL.qll. 2020-08-12 16:55:26 +01:00
lcartey@github.com
6f83c55ebd Java: Switch to low as a precision
Code Scanning doesn't support "very-low"
2020-08-12 13:48:59 +01:00
CodeQL CI
66541f260b Merge pull request #4012 from erik-krogh/getId
Approved by asgerf, esbena
2020-08-12 13:28:18 +01:00
Luke Cartey
56ff8cf084 Apply suggestions from code review
Co-authored-by: Felicity Chapman <felicitymay@github.com>
2020-08-12 13:12:06 +01:00
CodeQL CI
aa9dfa0d6f Merge pull request #4039 from intrigus-lgtm/patch-3
Approved by erik-krogh
2020-08-12 13:07:22 +01:00
Geoffrey White
b99ca60154 C++: Address review comments. 2020-08-12 12:56:28 +01:00
Jonas Jensen
b4679cb8cf C++: Autoformat fixup 2020-08-12 13:09:23 +02:00
Jonas Jensen
93d8d8eb1d C++: Demonstrate range analysis MulExpr bugs
Unless these issues can be reproduced in far less contrived code, I
don't think they will cause problems in practice.
2020-08-12 12:10:23 +02:00
lcartey@github.com
6b6172fa5b Java: ExternalAPIs: Further review comments
- Extra qldoc
 - Remove unnecessary module
2020-08-12 09:21:14 +01:00
Jonas Jensen
1ee96a4b4f C++: SimpleRangeAnalysis: unsigned multiplication 2020-08-12 10:03:04 +02:00
Robert Marsh
e80cc63219 Merge pull request #3861 from dilanbhalla/privatedata
C++: Private Data File/Buffer Writes
2020-08-11 15:49:31 -04:00
Geoffrey White
a655124213 C++: I think this is more correct. 2020-08-11 17:28:31 +01:00
Geoffrey White
50558257fc C++: Change note. 2020-08-11 17:05:49 +01:00
Geoffrey White
128b8328b9 C++: Autoformat. 2020-08-11 17:03:03 +01:00
Geoffrey White
f62ad75048 C++: Taint through std::string operator+=. 2020-08-11 17:03:02 +01:00
Geoffrey White
cf6f530823 C++: Taint through std::string operator+. 2020-08-11 16:58:55 +01:00
Geoffrey White
a57dfd6b67 C++: Taint through std::string append. 2020-08-11 16:54:39 +01:00
Geoffrey White
f824a893ca C++: Add test cases for appending strings. 2020-08-11 16:50:52 +01:00
Geoffrey White
030ab4f626 C++: Add string append operators to the test (changes layout). 2020-08-11 16:47:56 +01:00
Jonas Jensen
2ea25b9d90 C++: Precise printing of integer bounds
The pretty-printing of a QL `float` didn't include enough digits to tell
whether a large number had accurate bounds. The `toString` value of a
float appears to be more precise.
2020-08-11 16:48:01 +02:00
lcartey@github.com
e1d4b98923 Java: Add further missing </p> to qhelp 2020-08-11 15:28:55 +01:00
lcartey@github.com
8a65dd2cd6 Java: Address review comments 2020-08-11 15:28:06 +01:00
Erik Krogh Kristensen
656ff9c441 autoformat 2020-08-11 15:40:30 +02:00
Anders Schack-Mulligen
21246624b4 Java: Add PrintWriter.format as XSS sink. 2020-08-11 15:15:39 +02:00
Rasmus Lerchedahl Petersen
dd4d00293d Python: remaining class tests 2020-08-11 14:16:02 +02:00
Rasmus Lerchedahl Petersen
394991164f Python: Update test expectations 2020-08-11 13:05:35 +02:00
Rasmus Lerchedahl Petersen
f834d71bab Python: split out data model tests 2020-08-11 11:22:11 +02:00
Rasmus Lerchedahl Petersen
2c5de7f50e Python: fix r/l confusion 2020-08-11 10:48:23 +02:00
Jonas Jensen
0476b97f63 Merge pull request #3789 from dilanbhalla/cpp
C++ Memory Unsafe Functions
2020-08-11 10:09:37 +02:00
Rasmus Lerchedahl Petersen
12dfc4afd9 Python: clean up validity check code 2020-08-11 08:16:49 +02:00
Rasmus Lerchedahl Petersen
3929e01350 Python: tests for async iterators/context managers 2020-08-11 08:10:46 +02:00
Rasmus Lerchedahl Petersen
681657f070 Merge branch 'master' of github.com:github/codeql into SharedDataflow_Classes 2020-08-11 07:24:17 +02:00
intrigus-lgtm
5a3acc231e Fix typo 2020-08-11 01:01:53 +02:00
dilanbhalla
7bd5464b01 Update cpp/ql/src/experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.qhelp
Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com>
2020-08-10 15:43:16 -07:00
dilanbhalla
4dcaa7be57 pr fixes 2020-08-10 15:30:09 -07:00
dilanbhalla
dcfbb86674 pr fixes 2020-08-10 15:14:12 -07:00
Rasmus Lerchedahl Petersen
5da37f5cf4 Python: Update test expectations 2020-08-10 17:07:00 +02:00
Erik Krogh Kristensen
dc5167bbe7 autoformat 2020-08-10 11:52:45 +00:00
Jonas Jensen
1f432dc45f Merge pull request #4023 from geoffw0/loopdir
C++: Exclude decrementing unsigned counters from inconsistentLoopDirection.ql
2020-08-10 12:10:29 +02:00
Rasmus Lerchedahl Petersen
a963f15100 Python: format strings are unnecessary and mess up
For some reason, we got no results when format strings were present.
2020-08-10 11:54:24 +02:00
Erik Krogh Kristensen
85de5aa16b add deprecated modifier
Co-authored-by: Asger F <asgerf@github.com>
2020-08-10 10:51:21 +02:00
Rasmus Lerchedahl Petersen
959c6315c4 Python: update reference to fix tests 2020-08-10 09:24:45 +02:00
Erik Krogh Kristensen
410b696562 add deprecated aliases getId() forwarding to getIdentifier() 2020-08-10 09:11:38 +02:00
Rasmus Lerchedahl Petersen
639d914a47 Python: test Awaitable, framework for async test 2020-08-10 09:03:28 +02:00
CodeQL CI
7c4e10df17 Merge pull request #4014 from erik-krogh/stringify
Approved by esbena
2020-08-10 07:50:21 +01:00
Rasmus Lerchedahl Petersen
02478774c3 Python: tests for context managers 2020-08-10 08:11:25 +02:00
Rasmus Lerchedahl Petersen
5b7c7f933c Python: tests for numeric classes 2020-08-08 00:31:29 +02:00
Rasmus Lerchedahl Petersen
f6d6f91a42 Python: tests for containers 2020-08-07 23:39:42 +02:00
Rasmus Lerchedahl Petersen
aff4535965 Python: fix tests for descriptors 2020-08-07 23:07:58 +02:00
Arthur Baars
5874ecc28b Merge pull request #3976 from luchua-bc/java-unsecure-basic-auth
Java: Insecure basic authentication
2020-08-07 21:39:23 +02:00
Rasmus Lerchedahl Petersen
d84294df3d Python: Check that tests are valid 2020-08-07 20:07:02 +02:00
Geoffrey White
3cf11eca2a C++: And more test cases. 2020-08-07 17:30:07 +01:00
Erik Krogh Kristensen
aab2e6f803 update name of test file 2020-08-07 18:20:22 +02:00
Erik Krogh Kristensen
7670e7da97 retarget change-note for 1.26 2020-08-07 18:17:46 +02:00
Geoffrey White
7d491afaeb C++: More test cases. 2020-08-07 17:05:13 +01:00
Geoffrey White
b7d2e0ca63 C++: Make all the tests meaningful. 2020-08-07 14:18:28 +01:00
CodeQL CI
1b0cfc96b3 Merge pull request #4015 from erik-krogh/nonAbstract
Approved by asgerf
2020-08-07 13:44:23 +01:00
Geoffrey White
0ba59210fc Merge pull request #4020 from jbj/taint-range-based-for-ast
C++: Taint through RangeBasedForStmt (AST only)
2020-08-07 13:41:49 +01:00
Anders Schack-Mulligen
e3a12c5fea Merge pull request #4004 from Marcono1234/patch-2
[Java] Clarify Wildcard.hasUpperBound() doc
2020-08-07 13:06:13 +02:00
Tom Hvitved
c20d763490 Merge pull request #3951 from raulgarciamsft/users/raulgarciamsft/dataset_serialization
C#: DataSet serialization
2020-08-07 12:54:10 +02:00
Jonas Jensen
c8911ab973 C++: Test range-based-for with std::vector too 2020-08-07 12:40:00 +02:00
Anders Schack-Mulligen
77db87efb7 Merge pull request #3968 from rvermeulen/java-importable-cwe-090
Java: Move LDAP injection sinks, sanitizers, and additional taint steps to importable location
2020-08-07 11:57:51 +02:00
Arthur Baars
c177eff3d8 Merge pull request #4027 from aschackmull/java/weak-crypto-precision
Java: Update precision of java/weak-cryptographic-algorithm.
2020-08-07 10:31:38 +02:00
Anders Schack-Mulligen
f9de8eb3b4 Java: Update precision of java/weak-cryptographic-algorithm. 2020-08-07 09:40:21 +02:00
Anders Schack-Mulligen
05e956b374 Merge pull request #4022 from aibaars/int-to-long
Java: remove security tag from java/integer-multiplication-cast-to-long
2020-08-07 09:32:43 +02:00
Marcono1234
0e54b498b7 Clarify Wildcard.hasTypeBound() doc 2020-08-06 23:15:25 +02:00
Marcono1234
f477e09190 Clarify Wildcard.hasUpperBound() doc 2020-08-06 23:15:16 +02:00
Remco Vermeulen
3ae3a879d2 Fix qldoc grammar and style mistakes
Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com>
2020-08-06 23:00:03 +02:00
Raul Garcia
3682a902de Update csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qhelp
Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com>
2020-08-06 12:09:02 -07:00
Geoffrey White
6e18be43f3 C++: Change note. 2020-08-06 19:27:12 +01:00
Geoffrey White
0281456948 C++: Add a 1.26 change note file (what happened to the templates?) 2020-08-06 19:21:06 +01:00
Geoffrey White
0534c69c76 C++: Autoformat. 2020-08-06 19:11:46 +01:00
Geoffrey White
0b5b7fa095 C++: Fix another edge case. 2020-08-06 19:06:42 +01:00
Geoffrey White
b3f3f6d95a C++: Fix edge case. 2020-08-06 19:03:43 +01:00
Geoffrey White
cbf30e37ed C++: Fix the issue. 2020-08-06 18:50:18 +01:00
Geoffrey White
a7564c9e0e C++: Add a test of unsigned count-down loops. 2020-08-06 18:44:22 +01:00
Arthur Baars
f16c263393 Java: remove security tag from java/integer-multiplication-cast-to-long 2020-08-06 17:42:01 +02:00
Rasmus Lerchedahl Petersen
3db1ceeb70 Python: format ql 2020-08-06 15:42:14 +02:00
Rasmus Lerchedahl Petersen
614103c3b6 Python: Test calls rather than flows 2020-08-06 15:40:41 +02:00
Jonas Jensen
7cc877cbbb C++: Taint through RangeBasedForStmt (AST only) 2020-08-06 15:37:41 +02:00
Remco Vermeulen
408db412dc Add missing predicate qldoc 2020-08-06 13:29:02 +02:00
Remco Vermeulen
5a819422c1 Reuse Unit class from TaintTracking 2020-08-06 12:02:34 +02:00
Remco Vermeulen
7f7ad88dea Limit LdapAdditionalTaintStep to Ldap configuration 2020-08-06 11:35:03 +02:00
Anders Schack-Mulligen
205dd1aead Merge pull request #3881 from intrigus-lgtm/more-pathcreations
Java: Centralize and model additional path creations.
2020-08-06 11:21:39 +02:00
luchua-bc
b821f918e5 Address issues with matching empty host and host in a concatenated string 2020-08-06 01:53:29 +00:00
luchua-bc
9a8eed8440 Enhance address match 2020-08-05 19:57:31 +00:00
intrigus
1011325cf7 Accept test changes. 2020-08-05 21:45:41 +02:00
Remco Vermeulen
a1411407c1 Consolidate sanitizers into default sanitizer 2020-08-05 17:07:05 +02:00
Remco Vermeulen
0c09d66d43 Consolidate different sinks into a default sink. 2020-08-05 16:53:50 +02:00
Erik Krogh Kristensen
f1dc36244c update tests and queries that used getId() 2020-08-05 14:32:09 +00:00
yoff
e642808a75 Update python/ql/test/experimental/dataflow/coverage/classes.py
Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com>
2020-08-05 15:12:27 +02:00
Jonas Jensen
5f635aca36 Merge pull request #3768 from geoffw0/copymove
C++: Clean up ConversionConstructor.
2020-08-05 14:35:05 +02:00
Rasmus Lerchedahl Petersen
a89624698d Python: format ql 2020-08-05 14:28:28 +02:00
Rasmus Lerchedahl Petersen
81ad4552c9 Python: full list of magic methods to be tested 2020-08-05 13:30:30 +02:00
Erik Krogh Kristensen
cc5ef4d5e1 rename JsonSerializeCall to JsonStringifyCall 2020-08-05 13:22:41 +02:00
Erik Krogh Kristensen
b43d410ab1 add change log for JSON serializers 2020-08-05 12:14:56 +02:00
Erik Krogh Kristensen
f70cb2e7b3 add test for new JSON serializers 2020-08-05 12:14:56 +02:00
Erik Krogh Kristensen
5a3f67a682 introduce model for JSON.stringify and similar libraries 2020-08-05 12:14:51 +02:00
Anders Schack-Mulligen
9e78341e43 Merge pull request #3928 from rvermeulen/java-importable-cwe-113
Java: Move `HeaderSplittingSink` and `WhitelistedSource` into importable library
2020-08-05 10:16:00 +02:00
Erik Krogh Kristensen
67c4320287 make JumpStmt non abstract 2020-08-05 10:03:46 +02:00
Erik Krogh Kristensen
016bdc1614 make ControlStmt non abstract 2020-08-05 09:59:30 +02:00
Anders Schack-Mulligen
32d9d270fc Merge pull request #3948 from aibaars/java-3941
Java: stack trace exposure: address false positives
2020-08-05 09:31:01 +02:00
Jonas Jensen
ea0896c78b Merge pull request #3999 from MathiasVP/mathiasvp/range-based-for-loop-taint-tests
C++: Add tests for taint through range-based for loops
2020-08-05 09:11:53 +02:00
Raul Garcia (MSFT)
aa27eaf7e0 Addrssing the comments from https://github.com/github/codeql/pull/3951#discussion_r464894547 that I missed previously 2020-08-04 15:50:58 -07:00
Geoffrey White
9f5c37ccaa Merge branch 'master' into copymove 2020-08-04 15:41:27 +01:00
Erik Krogh Kristensen
5727e6f9f8 make CompoundAssignExpr non-abstract 2020-08-04 16:17:08 +02:00
Erik Krogh Kristensen
cf3f275aa1 make DestructuringPattern non-abstract 2020-08-04 16:02:32 +02:00
Rasmus Lerchedahl Petersen
d7c08f732d Merge branch 'master' of github.com:github/codeql into SharedDataflow_Classes 2020-08-04 16:01:42 +02:00
Erik Krogh Kristensen
0867c5567e rename getId() to getIdentifier() 2020-08-04 13:22:19 +02:00
Luke Cartey
5a96ee1a7b Remove parameter names from signatures
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
2020-08-04 09:41:40 +01:00
Luke Cartey
368572f1f0 Update java/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.qhelp
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
2020-08-04 09:40:59 +01:00
Luke Cartey
7928a02424 Add missing full stop.
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
2020-08-04 09:40:51 +01:00
Luke Cartey
e0c081a2af Add missing </p> tag
Co-authored-by: Felicity Chapman <felicitymay@github.com>
2020-08-04 09:40:28 +01:00
Raul Garcia (MSFT)
c52064af78 Fixing problems based on CR feedback.
https://github.com/github/codeql/pull/3951#pullrequestreview-458987208
2020-08-03 16:39:41 -07:00
luchua-bc
ff0dacf1d7 Optimize the TaintTracking 2020-08-03 00:52:47 +00:00
luchua-bc
b65a033302 Shorten the regex private domain match 2020-08-01 03:42:13 +00:00
luchua-bc
ff58abb7d3 Revamp the sink code 2020-08-01 03:25:02 +00:00
Mathias Vorreiter Pedersen
4990d00498 C++: Add taint tests demonstrating lack of taint through range based for loops 2020-07-31 09:57:35 +02:00
Mathias Vorreiter Pedersen
b88ef56cb4 C++: Add basic iterator definition that matches STL 2020-07-31 09:45:32 +02:00
Raul Garcia (MSFT)
a5dab4e768 removing a redundant line 2020-07-30 17:05:42 -07:00
luchua-bc
81de1b14d9 Revamp the source of path query 2020-07-30 19:16:48 +00:00
Raul Garcia (MSFT)
64f4613a3f Removing the options file as requested 2020-07-30 10:25:15 -07:00
Raul Garcia (MSFT)
9e74c183fe Fixing expected results after adding comments to the unit test .cs file 2020-07-30 10:24:24 -07:00
Raul Garcia (MSFT)
6f845b0044 Using CodeQL AutoFormat 2020-07-29 18:01:46 -07:00
Raul Garcia (MSFT)
7923c480af Fixing queries based on suggestions/comments.
TODO: Auto-formatting is still pending (need guidance on how to enable it on my environment). Thanks
2020-07-29 17:14:37 -07:00
Raul Garcia
83e9d052d9 Update csharp/ql/src/experimental/Security Features/Serialization/DataSetSerialization.qll
Co-authored-by: Jaroslav Lobačevski <novaisas@gmail.com>
2020-07-29 16:24:13 -07:00
Rasmus Lerchedahl Petersen
d32e2772a0 Python: some doc, a generator, and a corotuine 2020-07-29 15:52:56 +02:00
Rasmus Lerchedahl Petersen
488a7f4d01 Python: update test expectations 2020-07-28 21:46:45 +02:00
Rasmus Lerchedahl Petersen
eab64f125b Python: Dataflow, start on test for classes 2020-07-28 20:32:12 +02:00
luchua-bc
5520504658 Update expected results 2020-07-28 15:41:23 +00:00
luchua-bc
a91cc9b7ec Convert the query to path-problem 2020-07-28 15:36:12 +00:00
luchua-bc
7f911f00ee Rename to insecure basic auth 2020-07-28 11:40:21 +00:00
luchua-bc
248628b11e Enhance basic auth string search with a recursive method 2020-07-27 20:31:07 +00:00
luchua-bc
3a23451395 Enhance the query 2020-07-27 18:50:47 +00:00
Rasmus Lerchedahl Petersen
38acea633f Python: Dataflow, expand callable to classes 2020-07-27 17:58:21 +02:00
luchua-bc
01fb51829c Unsecure basic authentication 2020-07-24 20:35:09 +00:00
Remco Vermeulen
3320061178 Add and adjust QL docs for classes and predicates 2020-07-22 16:04:55 +02:00
Remco Vermeulen
2c42d3cca5 Extract additional taint steps
This is done for logical cohesion. We already have the capability of
extending additional taint steps by extending
`TaintTracking::AdditionalTaintStep`.
2020-07-22 16:04:55 +02:00
Remco Vermeulen
57e7411c0a Extract Ldap injection sanitizers to importable lib
This includes a new abstract class that represents all the Ldap injection
santizers and can be used to add additional santizers through
extension.
2020-07-22 16:04:55 +02:00
Remco Vermeulen
0d5f9113a3 Extract ldap injection sink into importable library 2020-07-22 16:04:55 +02:00
Raul Garcia (MSFT)
55473c65f1 Improving documentation 2020-07-20 13:54:23 -07:00
Raul Garcia (MSFT)
9d7d6b39cb Small fixes based on feedback 2020-07-20 11:14:59 -07:00
Remco Vermeulen
c2733ad22e Apply grammar suggestions
Co-authored-by: Anders Schack-Mulligen <aschackmull@users.noreply.github.com>
2020-07-20 14:55:00 +02:00
intrigus
f94055fa2c Move tainted path ad-hoc guard back. 2020-07-19 00:19:29 +02:00
intrigus
33526f61a8 Make path creation subclasses private. 2020-07-19 00:11:04 +02:00
intrigus
b705f7f3e9 Improve "PathCreation" Test. 2020-07-19 00:10:39 +02:00
intrigus
4570444c7e Rename to getAnInput and clarify doc. 2020-07-19 00:10:13 +02:00
Raul Garcia (MSFT)
5387294168 Moving to experimental as requested 2020-07-16 09:32:17 -07:00
Geoffrey White
c4940aaa86 Merge branch 'master' into copymove 2020-07-15 15:01:01 +01:00
Raul Garcia (MSFT)
3e0481b889 Queries to help on the detection based on misuse of DataSet and DataTable serialization that could lead to security problems.
https://go.microsoft.com/fwlink/?linkid=2132227
2020-07-14 17:54:54 -07:00
Raul Garcia (MSFT)
896cdf9b12 Merge branch 'master' of https://github.com/github/codeql 2020-07-14 11:16:51 -07:00
Geoffrey White
37158f46ed C++: Remove deprecated class from test. 2020-07-14 15:36:48 +01:00
Geoffrey White
3f6d8490e0 C++: Autoformat. 2020-07-14 15:09:12 +01:00
Geoffrey White
646efe2a20 C++: Deprecate ConversionConstructor. 2020-07-13 15:04:39 +01:00
Arthur Baars
c585b2e483 Java: stack trace exposure: address false positives 2020-07-13 15:26:55 +02:00
Geoffrey White
61178c5330 Merge branch 'master' into copymove 2020-07-13 14:11:12 +01:00
dilanbhalla
48e540fa9a minor fixes 2020-07-13 01:25:42 -07:00
dilanbhalla
db6d5c329f file/buffer write dataflow queries complete 2020-07-13 00:57:05 -07:00
Remco Vermeulen
c739c733fe Update class qldocs
Change the ql docs to meet the style-guide points 1 and 3 for
classes.
2020-07-09 17:31:37 +02:00
Remco Vermeulen
b3bb4cbf54 Rename and update qldoc of default safe header splitting source 2020-07-09 16:14:21 +02:00
Remco Vermeulen
b147be6fea Restrict SafeHeaderSplittingSource to RemoteFlowSource 2020-07-09 15:13:18 +02:00
Remco Vermeulen
782573ed43 Add and format qldocs according to the style guide. 2020-07-09 14:58:53 +02:00
Remco Vermeulen
4ad6357cd7 Add missing Java import 2020-07-09 14:54:46 +02:00
Remco Vermeulen
7435dac3d2 Move source and sink into importable library 2020-07-09 14:53:59 +02:00
intrigus
641c5df79f Centralize and model additional path creations. 2020-07-09 14:48:47 +02:00
Remco Vermeulen
b66f391c31 Extend source and sink from DataFlow::Node instead of DataFlow::exprNode 2020-07-09 14:39:08 +02:00
Remco Vermeulen
fed506a12f Rename TrustedSource to SafeHeaderSplittingSource 2020-07-09 14:36:23 +02:00
dilanbhalla
6e6921b11e implemented pr fixes 2020-07-08 09:23:52 -07:00
dilanbhalla
05a4798b5e working on implementing pr fixes 2020-07-08 09:19:46 -07:00
Remco Vermeulen
5f560e0465 Extract HeaderSplittingSink and WhitelistedSource
- Extract `HeaderSplittingSink` and `WhitelistedSource` into an
importable library.
- Rename the existing `HeaderSplittingSink` implementation to
`ServletHeaderSplittingSink`.
2020-07-08 17:17:24 +02:00
dilanbhalla
3b9daa2db2 added pr fixes 2020-07-07 11:05:39 -07:00
dilanbhalla
d201c4ba8a fixed pr suggestions for tags/formatting 2020-07-07 09:34:04 -07:00
luchua-bc
d6e9b07a9e Add JBoss BasicLogger and SciJava Logger 2020-07-03 22:34:48 +00:00
lcartey@github.com
b242a61701 Java: Untrusted data used in external APIs
This commit adds two queries for identifying external APIs which are
used with untrusted data.

These queries are intended to facilitate a security review of the
application, and will report any external API which is called with
untrusted data. The purpose of this is to:
 - review how untrusted data flows through this application
 - identify opportunities to improve taint modeling of sinks and taint
   steps.
As a result this is not suitable for integration into a developer
workflow, as it will likely have high false positive rate, but it may
help identify false negatives for other queries.
2020-07-03 17:32:08 +01:00
luchua-bc
6d329bce6e Add Apache Commons Logging and debugv method 2020-07-03 01:13:11 +00:00
dilanbhalla
263f00784f formatting 2020-07-01 09:25:09 -07:00
dilanbhalla
25bfc3a168 fixed references and used autoformat 2020-07-01 09:23:36 -07:00
dilanbhalla
259654b1a4 moved library to experimental 2020-06-30 18:04:41 -07:00
dilanbhalla
e1130a2bfa moved privatedata to experimental 2020-06-30 17:58:24 -07:00
dilanbhalla
3fdd11a9b5 scanf fixes, still need to update qhelp file 2020-06-30 17:22:29 -07:00
dilanbhalla
f462156cdf private data file/buffer write 2020-06-30 12:09:50 -07:00
Geoffrey White
3016798101 Merge branch 'master' into copymove 2020-06-30 16:20:41 +01:00
Geoffrey White
c57c016ced C++: Go the other way. 2020-06-30 16:16:00 +01:00
dilanbhalla
0552f9b0cc memory unsafe scan functions 2020-06-24 11:47:34 -07:00
Geoffrey White
dd19ee47a1 C++: Clean up ConversionConstructor. 2020-06-23 11:22:59 +01:00
luchua-bc
9affa157b6 Add Log4J 2 and a new search string secret 2020-06-02 03:21:27 +00:00
Raul Garcia (MSFT)
f051f46ee9 Merge branch 'master' of https://github.com/semmle/ql 2020-05-05 13:37:03 -07:00
Raul Garcia (MSFT)
908d789f1b Merge branch 'master' of https://github.com/semmle/ql 2019-11-22 13:25:22 -08:00
Raul Garcia
e44229435c Merge pull request #6 from Semmle/master
Merge
2019-10-26 19:05:58 -07:00
166 changed files with 8573 additions and 2075 deletions

View File

@@ -0,0 +1,23 @@
# Improvements to C/C++ analysis
The following changes in version 1.26 affect C/C++ analysis in all applications.
## General improvements
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
| Inconsistent direction of for loop (`cpp/inconsistent-loop-direction`) | Fewer false positive results | The query now accounts for intentional wrapping of an unsigned loop counter. |
| Comparison result is always the same (`cpp/constant-comparison`) | More correct results | Bounds on expressions involving multiplication can now be determined in more cases. |
## Changes to libraries
* The models library now models more taint flows through `std::string`.
* The `SimpleRangeAnalysis` library now supports multiplications of the form
`e1 * e2` when `e1` and `e2` are unsigned.

View File

@@ -0,0 +1,30 @@
# Improvements to JavaScript analysis
## General improvements
* Support for the following frameworks and libraries has been improved:
- [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify)
- [fast-safe-stringify](https://www.npmjs.com/package/fast-safe-stringify)
- [javascript-stringify](https://www.npmjs.com/package/javascript-stringify)
- [js-stringify](https://www.npmjs.com/package/js-stringify)
- [json-stable-stringify](https://www.npmjs.com/package/json-stable-stringify)
- [json-stringify-safe](https://www.npmjs.com/package/json-stringify-safe)
- [json3](https://www.npmjs.com/package/json3)
- [object-inspect](https://www.npmjs.com/package/object-inspect)
- [pretty-format](https://www.npmjs.com/package/pretty-format)
- [stringify-object](https://www.npmjs.com/package/stringify-object)
## New queries
| **Query** | **Tags** | **Purpose** |
|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
## Changes to libraries

View File

@@ -50,7 +50,12 @@ predicate illDefinedDecrForStmt(
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(lesserOperand)) and
// `initialCondition` < `terminalCondition`
(
upperBound(initialCondition) < lowerBound(terminalCondition)
upperBound(initialCondition) < lowerBound(terminalCondition) and
(
// exclude cases where the loop counter is `unsigned` (where wrapping behaviour can be used deliberately)
v.getUnspecifiedType().(IntegralType).isSigned() or
initialCondition.getValue().toInt() = 0
)
or
(forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue())
)

View File

@@ -18,6 +18,9 @@ Expr getTest() {
or
// boost tests; http://www.boost.org/
result.(FunctionCall).getTarget().hasQualifiedName("boost::unit_test", "make_test_case")
or
// googletest tests; https://github.com/google/googletest/
result.(FunctionCall).getTarget().hasQualifiedName("testing::internal", "MakeAndRegisterTestInfo")
}
from File f, int n

View File

@@ -1,5 +1,13 @@
/**
* Provides classes for identifying and reasoning about Microsoft source code
* annotation language (SAL) macros.
*/
import cpp
/**
* A SAL macro defined in `sal.h` or a similar header file.
*/
class SALMacro extends Macro {
SALMacro() {
exists(string filename | filename = this.getFile().getBaseName() |
@@ -20,27 +28,34 @@ class SALMacro extends Macro {
}
pragma[noinline]
predicate isTopLevelMacroAccess(MacroAccess ma) { not exists(ma.getParentInvocation()) }
private predicate isTopLevelMacroAccess(MacroAccess ma) { not exists(ma.getParentInvocation()) }
/**
* An invocation of a SAL macro (excluding invocations inside other macros).
*/
class SALAnnotation extends MacroInvocation {
SALAnnotation() {
this.getMacro() instanceof SALMacro and
isTopLevelMacroAccess(this)
}
/** Returns the `Declaration` annotated by `this`. */
/** Gets the `Declaration` annotated by `this`. */
Declaration getDeclaration() {
annotatesAt(this, result.getADeclarationEntry(), _, _) and
not result instanceof Type // exclude typedefs
}
/** Returns the `DeclarationEntry` annotated by `this`. */
/** Gets the `DeclarationEntry` annotated by `this`. */
DeclarationEntry getDeclarationEntry() {
annotatesAt(this, result, _, _) and
not result instanceof TypeDeclarationEntry // exclude typedefs
}
}
/**
* A SAL macro indicating that the return value of a function should always be
* checked.
*/
class SALCheckReturn extends SALAnnotation {
SALCheckReturn() {
exists(SALMacro m | m = this.getMacro() |
@@ -50,6 +65,10 @@ class SALCheckReturn extends SALAnnotation {
}
}
/**
* A SAL macro indicating that a pointer variable or return value should not be
* `NULL`.
*/
class SALNotNull extends SALAnnotation {
SALNotNull() {
exists(SALMacro m | m = this.getMacro() |
@@ -69,6 +88,9 @@ class SALNotNull extends SALAnnotation {
}
}
/**
* A SAL macro indicating that a value may be `NULL`.
*/
class SALMaybeNull extends SALAnnotation {
SALMaybeNull() {
exists(SALMacro m | m = this.getMacro() |
@@ -79,13 +101,29 @@ class SALMaybeNull extends SALAnnotation {
}
}
/**
* A parameter annotated by one or more SAL annotations.
*/
class SALParameter extends Parameter {
/** One of this parameter's annotations. */
SALAnnotation a;
SALParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) }
predicate isIn() { a.getMacroName().toLowerCase().matches("%\\_in%") }
predicate isOut() { a.getMacroName().toLowerCase().matches("%\\_out%") }
predicate isInOut() { a.getMacroName().toLowerCase().matches("%\\_inout%") }
}
///////////////////////////////////////////////////////////////////////////////
// Implementation details
/**
* Holds if `a` annotates the declaration entry `d` and
* its start position is the `idx`th position in `file` that holds a SAL element.
*/
predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, int idx) {
private predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, int idx) {
annotatesAtPosition(a.(SALElement).getStartPosition(), d, file, idx)
}
@@ -109,22 +147,6 @@ private predicate annotatesAtPosition(SALPosition pos, DeclarationEntry d, File
)
}
/**
* A parameter annotated by one or more SAL annotations.
*/
class SALParameter extends Parameter {
/** One of this parameter's annotations. */
SALAnnotation a;
SALParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) }
predicate isIn() { a.getMacroName().toLowerCase().matches("%\\_in%") }
predicate isOut() { a.getMacroName().toLowerCase().matches("%\\_out%") }
predicate isInOut() { a.getMacroName().toLowerCase().matches("%\\_inout%") }
}
/**
* A SAL element, that is, a SAL annotation or a declaration entry
* that may have SAL annotations.

View File

@@ -0,0 +1,25 @@
///// Library routines /////
int scanf(const char *format, ...);
int sscanf(const char *str, const char *format, ...);
int fscanf(const char *str, const char *format, ...);
///// EXAMPLES /////
int main(int argc, char **argv)
{
// BAD, do not use scanf without specifying a length first
char buf1[10];
scanf("%s", buf1);
// GOOD, length is specified. The length should be one less than the size of the buffer, since the last character is the NULL terminator.
char buf2[10];
sscanf(buf2, "%9s");
// BAD, do not use scanf without specifying a length first
char file[10];
fscanf(file, "%s", buf2);
return 0;
}

View File

@@ -0,0 +1,25 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>It is bad practice to use any of the <code>scanf</code> functions without including a specified length within the format parameter, as it will be vulnerable to buffer overflows.</p>
</overview>
<recommendation>
<p>Specify a length within the format string parameter, and make this length one less than the size of the buffer, since the last character should be reserved for the NULL terminator.</p>
</recommendation>
<example>
<p>The following example demonstrates safe and unsafe uses of <code>scanf</code> type functions.</p>
<sample src="MemoryUnsafeFunctionScan.cpp" />
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,19 @@
/**
* @name Scanf function without a specified length
* @description Use of one of the scanf functions without a specified length.
* @kind problem
* @problem.severity warning
* @id cpp/memory-unsafe-function-scan
* @tags reliability
* security
* external/cwe/cwe-120
*/
import cpp
import semmle.code.cpp.commons.Scanf
from FunctionCall call, ScanfFunction sff
where
call.getTarget() = sff and
call.getArgument(sff.getFormatParameterIndex()).getValue().regexpMatch(".*%l?s.*")
select call, "Dangerous use of one of the scanf functions"

View File

@@ -0,0 +1,32 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Private data that is stored in a file or buffer unencrypted is accessible to an attacker who gains access to the
storage.</p>
</overview>
<recommendation>
<p>Ensure that private data is always encrypted before being stored.
It may be wise to encrypt information before it is put into a buffer that may be readable in memory.</p>
<p>In general, decrypt private data only at the point where it is necessary for it to be used in
cleartext.</p>
</recommendation>
<references>
<li><a href="https://owasp.org/www-project-top-ten/OWASP_Top_Ten_2017/Top_10-2017_A3-Sensitive_Data_Exposure">OWASP Sensitive_Data_Exposure</a></li>
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
<!-- LocalWords: CWE
-->
</references>
</qhelp>

View File

@@ -0,0 +1,21 @@
/**
* @name Exposure of private information
* @description If private information is written to an external location, it may be accessible by
* unauthorized persons.
* @kind path-problem
* @problem.severity error
* @id cpp/private-cleartext-write
* @tags security
* external/cwe/cwe-359
*/
import cpp
import experimental.semmle.code.cpp.security.PrivateCleartextWrite
import experimental.semmle.code.cpp.security.PrivateCleartextWrite::PrivateCleartextWrite
import DataFlow::PathGraph
from WriteConfig b, DataFlow::PathNode source, DataFlow::PathNode sink
where b.hasFlowPath(source, sink)
select sink.getNode(),
"This write into the external location '" + sink + "' may contain unencrypted data from $@",
source, "this source."

View File

@@ -0,0 +1,63 @@
/**
* Provides a taint-tracking configuration for reasoning about private information flowing unencrypted to an external location.
*/
import cpp
import semmle.code.cpp.dataflow.TaintTracking
import experimental.semmle.code.cpp.security.PrivateData
import semmle.code.cpp.security.FileWrite
import semmle.code.cpp.security.BufferWrite
import semmle.code.cpp.dataflow.TaintTracking
module PrivateCleartextWrite {
/**
* A data flow source for private information flowing unencrypted to an external location.
*/
abstract class Source extends DataFlow::ExprNode { }
/**
* A data flow sink for private information flowing unencrypted to an external location.
*/
abstract class Sink extends DataFlow::ExprNode { }
/**
* A sanitizer for private information flowing unencrypted to an external location.
*/
abstract class Sanitizer extends DataFlow::ExprNode { }
/** A call to any method whose name suggests that it encodes or encrypts the parameter. */
class ProtectSanitizer extends Sanitizer {
ProtectSanitizer() {
exists(Function m, string s |
this.getExpr().(FunctionCall).getTarget() = m and
m.getName().regexpMatch("(?i).*" + s + ".*")
|
s = "protect" or s = "encode" or s = "encrypt"
)
}
}
class WriteConfig extends TaintTracking::Configuration {
WriteConfig() { this = "Write configuration" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
}
class PrivateDataSource extends Source {
PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr }
}
class WriteSink extends Sink {
WriteSink() {
exists(FileWrite f, BufferWrite b |
this.asExpr() = f.getASource()
or
this.asExpr() = b.getAChild()
)
}
}
}

View File

@@ -0,0 +1,53 @@
/**
* Provides classes and predicates for identifying private data and functions for security.
*
* 'Private' data in general is anything that would compromise user privacy if exposed. This
* library tries to guess where private data may either be stored in a variable or produced by a
* function.
*
* This library is not concerned with credentials. See `SensitiveActions` for expressions related
* to credentials.
*/
import cpp
/** A string for `match` that identifies strings that look like they represent private data. */
private string privateNames() {
// Inspired by the list on https://cwe.mitre.org/data/definitions/359.html
// Government identifiers, such as Social Security Numbers
result = "%social%security%number%" or
// Contact information, such as home addresses and telephone numbers
result = "%postcode%" or
result = "%zipcode%" or
// result = "%telephone%" or
// Geographic location - where the user is (or was)
result = "%latitude%" or
result = "%longitude%" or
// Financial data - such as credit card numbers, salary, bank accounts, and debts
result = "%creditcard%" or
result = "%salary%" or
result = "%bankaccount%" or
// Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc.
// result = "%email%" or
// result = "%mobile%" or
result = "%employer%" or
// Health - medical conditions, insurance status, prescription records
result = "%medical%"
}
/** An expression that might contain private data. */
abstract class PrivateDataExpr extends Expr { }
/** A functiond call that might produce private data. */
class PrivateFunctionCall extends PrivateDataExpr, FunctionCall {
PrivateFunctionCall() {
exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames()))
}
}
/** An access to a variable that might contain private data. */
class PrivateVariableAccess extends PrivateDataExpr, VariableAccess {
PrivateVariableAccess() {
exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames()))
}
}

View File

@@ -214,6 +214,9 @@ abstract class ImplicitConversionFunction extends MemberFunction {
}
/**
* DEPRECATED: as of C++11 this class does not correspond perfectly with the
* language definition of a converting constructor.
*
* A C++ constructor that also defines an implicit conversion. For example the
* function `MyClass` in the following code is a `ConversionConstructor`:
* ```
@@ -225,15 +228,16 @@ abstract class ImplicitConversionFunction extends MemberFunction {
* };
* ```
*/
class ConversionConstructor extends Constructor, ImplicitConversionFunction {
deprecated class ConversionConstructor extends Constructor, ImplicitConversionFunction {
ConversionConstructor() {
strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and
not hasSpecifier("explicit") and
not this instanceof CopyConstructor
not hasSpecifier("explicit")
}
override string getAPrimaryQlClass() {
not this instanceof MoveConstructor and result = "ConversionConstructor"
not this instanceof CopyConstructor and
not this instanceof MoveConstructor and
result = "ConversionConstructor"
}
/** Gets the type this `ConversionConstructor` takes as input. */

View File

@@ -65,6 +65,15 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
// tracking. The flow from expression `x` into `x++` etc. is handled in the
// case above.
exprTo = DataFlow::getAnAccessToAssignedVariable(exprFrom.(PostfixCrementOperation))
or
// In `for (char c : s) { ... c ... }`, this rule propagates taint from `s`
// to `c`.
exists(RangeBasedForStmt rbf |
exprFrom = rbf.getRange() and
// It's guaranteed up to at least C++20 that the range-based for loop
// desugars to a variable with an initializer.
exprTo = rbf.getVariable().getInitializer().getExpr()
)
)
or
// Taint can flow through modeled functions

View File

@@ -7,9 +7,17 @@ import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Taint
/**
* Model for C++ conversion constructors.
* Model for C++ conversion constructors. As of C++11 this does not correspond
* perfectly with the language definition of a converting constructor, however,
* it does correspond with the constructors we are confident taint should flow
* through.
*/
class ConversionConstructorModel extends ConversionConstructor, TaintFunction {
class ConversionConstructorModel extends Constructor, TaintFunction {
ConversionConstructorModel() {
strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and
not hasSpecifier("explicit")
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// taint flow from the first constructor argument to the returned object
input.isParameter(0) and

View File

@@ -1,5 +1,12 @@
import semmle.code.cpp.models.interfaces.Taint
/**
* The `std::basic_string` template class.
*/
class StdBasicString extends TemplateClass {
StdBasicString() { this.hasQualifiedName("std", "basic_string") }
}
/**
* The standard function `std::string.c_str`.
*/
@@ -12,3 +19,51 @@ class StdStringCStr extends TaintFunction {
output.isReturnValue()
}
}
/**
* The `std::string` function `operator+`.
*/
class StdStringPlus extends TaintFunction {
StdStringPlus() {
this.hasQualifiedName("std", "operator+") and
this.getUnspecifiedType() = any(StdBasicString s).getAnInstantiation()
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from parameters to return value
(
input.isParameterDeref(0) or
input.isParameterDeref(1)
) and
output.isReturnValue()
}
}
/**
* The `std::string` functions `operator+=` and `append`.
*/
class StdStringAppend extends TaintFunction {
StdStringAppend() {
this.hasQualifiedName("std", "basic_string", "operator+=") or
this.hasQualifiedName("std", "basic_string", "append")
}
/**
* Gets the index of a parameter to this function that is a string (or
* character).
*/
int getAStringParameter() {
getParameter(result).getType() instanceof PointerType or
getParameter(result).getType() instanceof ReferenceType or
getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT`
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from parameter to string itself (qualifier) and return value
input.isParameterDeref(getAStringParameter()) and
(
output.isQualifierObject() or
output.isReturnValueDeref()
)
}
}

View File

@@ -156,6 +156,10 @@ float safeFloor(float v) {
result = v
}
private class UnsignedMulExpr extends MulExpr {
UnsignedMulExpr() { this.getType().(IntegralType).isUnsigned() }
}
/** Set of expressions which we know how to analyze. */
private predicate analyzableExpr(Expr e) {
// The type of the expression must be arithmetic. We reuse the logic in
@@ -178,6 +182,8 @@ private predicate analyzableExpr(Expr e) {
or
e instanceof SubExpr
or
e instanceof UnsignedMulExpr
or
e instanceof AssignExpr
or
e instanceof AssignAddExpr
@@ -278,6 +284,10 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria
or
exists(SubExpr subExpr | e = subExpr | exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar))
or
exists(UnsignedMulExpr mulExpr | e = mulExpr |
exprDependsOnDef(mulExpr.getAnOperand(), srcDef, srcVar)
)
or
exists(AssignExpr addExpr | e = addExpr | exprDependsOnDef(addExpr.getRValue(), srcDef, srcVar))
or
exists(AssignAddExpr addExpr | e = addExpr |
@@ -625,6 +635,13 @@ private float getLowerBoundsImpl(Expr expr) {
result = addRoundingDown(xLow, -yHigh)
)
or
exists(UnsignedMulExpr mulExpr, float xLow, float yLow |
expr = mulExpr and
xLow = getFullyConvertedLowerBounds(mulExpr.getLeftOperand()) and
yLow = getFullyConvertedLowerBounds(mulExpr.getRightOperand()) and
result = xLow * yLow
)
or
exists(AssignExpr assign |
expr = assign and
result = getFullyConvertedLowerBounds(assign.getRValue())
@@ -794,6 +811,13 @@ private float getUpperBoundsImpl(Expr expr) {
result = addRoundingUp(xHigh, -yLow)
)
or
exists(UnsignedMulExpr mulExpr, float xHigh, float yHigh |
expr = mulExpr and
xHigh = getFullyConvertedUpperBounds(mulExpr.getLeftOperand()) and
yHigh = getFullyConvertedUpperBounds(mulExpr.getRightOperand()) and
result = xHigh * yHigh
)
or
exists(AssignExpr assign |
expr = assign and
result = getFullyConvertedUpperBounds(assign.getRValue())

View File

@@ -0,0 +1,21 @@
edges
| test.cpp:77:16:77:22 | medical | test.cpp:78:24:78:27 | temp |
| test.cpp:81:17:81:20 | call to func | test.cpp:82:24:82:28 | buff5 |
| test.cpp:81:22:81:28 | medical | test.cpp:81:17:81:20 | call to func |
nodes
| test.cpp:57:9:57:18 | theZipcode | semmle.label | theZipcode |
| test.cpp:74:24:74:30 | medical | semmle.label | medical |
| test.cpp:77:16:77:22 | medical | semmle.label | medical |
| test.cpp:78:24:78:27 | temp | semmle.label | temp |
| test.cpp:81:17:81:20 | call to func | semmle.label | call to func |
| test.cpp:81:22:81:28 | medical | semmle.label | medical |
| test.cpp:82:24:82:28 | buff5 | semmle.label | buff5 |
| test.cpp:96:37:96:46 | theZipcode | semmle.label | theZipcode |
| test.cpp:99:42:99:51 | theZipcode | semmle.label | theZipcode |
#select
| test.cpp:57:9:57:18 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:57:9:57:18 | theZipcode | this source. |
| test.cpp:74:24:74:30 | medical | This write into the external location 'medical' may contain unencrypted data from $@ | test.cpp:74:24:74:30 | medical | this source. |
| test.cpp:78:24:78:27 | temp | This write into the external location 'temp' may contain unencrypted data from $@ | test.cpp:77:16:77:22 | medical | this source. |
| test.cpp:82:24:82:28 | buff5 | This write into the external location 'buff5' may contain unencrypted data from $@ | test.cpp:81:22:81:28 | medical | this source. |
| test.cpp:96:37:96:46 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:96:37:96:46 | theZipcode | this source. |
| test.cpp:99:42:99:51 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:99:42:99:51 | theZipcode | this source. |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql

View File

@@ -0,0 +1,105 @@
#define FILE int
#define wchar char
#define size_t int
typedef int streamsize;
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
int fputs(const char *s, FILE *stream);
int fputc(int c, FILE *stream);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *s, const char *format, ...);
size_t strlen(const char *s);
namespace std
{
template <class charT>
struct char_traits;
template <class charT, class traits = char_traits<charT>>
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */
{
public:
typedef charT char_type;
basic_ostream<charT, traits> &write(const char_type *s, streamsize n);
};
template <class charT, class traits = char_traits<charT>>
class basic_ofstream : public basic_ostream<charT, traits>
{
public:
};
template <class charT, class traits>
basic_ostream<charT, traits> &operator<<(basic_ostream<charT, traits> &, const charT *);
typedef basic_ostream<char> ostream;
typedef basic_ofstream<char> ofstream;
}; // namespace std
using namespace std;
char *encrypt(char *buffer)
{
return buffer;
}
char *func(char *buffer)
{
return buffer;
}
// test for CleartextFileWrite
void file()
{
char *theZipcode = "cleartext zipcode!";
FILE *file;
// BAD: write zipcode to file in cleartext
fputs(theZipcode, file);
// GOOD: encrypt first
char *encrypted = encrypt(theZipcode);
fwrite(encrypted, sizeof(encrypted), 1, file);
}
// test for CleartextBufferWrite
int main(int argc, char **argv)
{
char *medical = "medical";
char *buff1;
char *buff2;
char *buff3;
char *buff4;
// BAD: write medical to buffer in cleartext
sprintf(buff1, "%s", medical);
// BAD: write medical to buffer in cleartext
char *temp = medical;
sprintf(buff2, "%s", temp);
// BAD: write medical to buffer in cleartext
char *buff5 = func(medical);
sprintf(buff3, "%s", buff5);
char *buff6 = encrypt(medical);
// GOOD: encrypt first
sprintf(buff4, "%s", buff6);
}
// test for CleartextFileWrite
void stream()
{
char *theZipcode = "cleartext zipcode!";
ofstream mystream;
// BAD: write zipcode to file in cleartext
mystream << "the zipcode is: " << theZipcode;
// BAD: write zipcode to file in cleartext
(mystream << "the zipcode is: ").write(theZipcode, strlen(theZipcode));
// GOOD: encrypt first
char *encrypted = encrypt(theZipcode);
mystream << "the zipcode is: " << encrypted;
(mystream << "the zipcode is: ").write(encrypted, strlen(encrypted));
}

View File

@@ -0,0 +1,25 @@
///// Library routines /////
int scanf(const char *format, ...);
int sscanf(const char *str, const char *format, ...);
int fscanf(const char *str, const char *format, ...);
///// Test code /////
int main(int argc, char **argv)
{
// BAD, do not use scanf without specifying a length first
char buf1[10];
scanf("%s", buf1);
// GOOD, length is specified
char buf2[10];
sscanf(buf2, "%9s");
// BAD, do not use scanf without specifying a length first
char file[10];
fscanf(file, "%s", buf2);
return 0;
}

View File

@@ -0,0 +1,2 @@
| MemoryUnsafeFunctionScan.cpp:14:5:14:9 | call to scanf | Dangerous use of one of the scanf functions |
| MemoryUnsafeFunctionScan.cpp:22:5:22:10 | call to fscanf | Dangerous use of one of the scanf functions |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.ql

View File

@@ -308,99 +308,230 @@
| movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT |
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT |
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:11:65:11 | call to operator= | TAINT |
| stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | |
| stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT |
| stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | |
| stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:74:7:74:7 | b | |
| stl.cpp:69:16:69:21 | call to source | stl.cpp:69:16:69:24 | call to basic_string | TAINT |
| stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:73:7:73:7 | c | |
| stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:75:7:75:7 | c | |
| stl.cpp:74:7:74:7 | b | stl.cpp:74:9:74:13 | call to c_str | TAINT |
| stl.cpp:75:7:75:7 | c | stl.cpp:75:9:75:13 | call to c_str | TAINT |
| stl.cpp:80:20:80:22 | call to basic_stringstream | stl.cpp:83:2:83:4 | ss1 | |
| stl.cpp:80:20:80:22 | call to basic_stringstream | stl.cpp:89:7:89:9 | ss1 | |
| stl.cpp:80:20:80:22 | call to basic_stringstream | stl.cpp:94:7:94:9 | ss1 | |
| stl.cpp:80:25:80:27 | call to basic_stringstream | stl.cpp:84:2:84:4 | ss2 | |
| stl.cpp:80:25:80:27 | call to basic_stringstream | stl.cpp:90:7:90:9 | ss2 | |
| stl.cpp:80:25:80:27 | call to basic_stringstream | stl.cpp:95:7:95:9 | ss2 | |
| stl.cpp:80:30:80:32 | call to basic_stringstream | stl.cpp:85:2:85:4 | ss3 | |
| stl.cpp:80:30:80:32 | call to basic_stringstream | stl.cpp:91:7:91:9 | ss3 | |
| stl.cpp:80:30:80:32 | call to basic_stringstream | stl.cpp:96:7:96:9 | ss3 | |
| stl.cpp:80:35:80:37 | call to basic_stringstream | stl.cpp:86:2:86:4 | ss4 | |
| stl.cpp:80:35:80:37 | call to basic_stringstream | stl.cpp:92:7:92:9 | ss4 | |
| stl.cpp:80:35:80:37 | call to basic_stringstream | stl.cpp:97:7:97:9 | ss4 | |
| stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:87:2:87:4 | ss5 | |
| stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:93:7:93:9 | ss5 | |
| stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:98:7:98:9 | ss5 | |
| stl.cpp:81:16:81:21 | call to source | stl.cpp:81:16:81:24 | call to basic_string | TAINT |
| stl.cpp:81:16:81:24 | call to basic_string | stl.cpp:87:9:87:9 | t | |
| stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:89:7:89:9 | ss1 | |
| stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:94:7:94:9 | ss1 | |
| stl.cpp:84:2:84:4 | ref arg ss2 | stl.cpp:90:7:90:9 | ss2 | |
| stl.cpp:84:2:84:4 | ref arg ss2 | stl.cpp:95:7:95:9 | ss2 | |
| stl.cpp:85:2:85:4 | ref arg ss3 | stl.cpp:91:7:91:9 | ss3 | |
| stl.cpp:85:2:85:4 | ref arg ss3 | stl.cpp:96:7:96:9 | ss3 | |
| stl.cpp:86:2:86:4 | ref arg ss4 | stl.cpp:92:7:92:9 | ss4 | |
| stl.cpp:86:2:86:4 | ref arg ss4 | stl.cpp:97:7:97:9 | ss4 | |
| stl.cpp:87:2:87:4 | ref arg ss5 | stl.cpp:93:7:93:9 | ss5 | |
| stl.cpp:87:2:87:4 | ref arg ss5 | stl.cpp:98:7:98:9 | ss5 | |
| stl.cpp:101:32:101:37 | source | stl.cpp:106:9:106:14 | source | |
| stl.cpp:103:20:103:22 | call to basic_stringstream | stl.cpp:105:2:105:4 | ss1 | |
| stl.cpp:103:20:103:22 | call to basic_stringstream | stl.cpp:108:7:108:9 | ss1 | |
| stl.cpp:103:20:103:22 | call to basic_stringstream | stl.cpp:110:7:110:9 | ss1 | |
| stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:106:2:106:4 | ss2 | |
| stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:109:7:109:9 | ss2 | |
| stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:111:7:111:9 | ss2 | |
| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:108:7:108:9 | ss1 | |
| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:110:7:110:9 | ss1 | |
| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:109:7:109:9 | ss2 | |
| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:111:7:111:9 | ss2 | |
| stl.cpp:124:16:124:28 | call to basic_string | stl.cpp:125:7:125:11 | path1 | |
| stl.cpp:124:17:124:26 | call to user_input | stl.cpp:124:16:124:28 | call to basic_string | TAINT |
| stl.cpp:125:7:125:11 | path1 | stl.cpp:125:13:125:17 | call to c_str | TAINT |
| stl.cpp:128:10:128:19 | call to user_input | stl.cpp:128:10:128:21 | call to basic_string | TAINT |
| stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:128:2:128:21 | ... = ... | |
| stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:129:7:129:11 | path2 | |
| stl.cpp:129:7:129:11 | path2 | stl.cpp:129:13:129:17 | call to c_str | TAINT |
| stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT |
| stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | |
| stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT |
| stl.cpp:137:19:137:24 | call to source | stl.cpp:140:17:140:18 | cs | |
| stl.cpp:137:19:137:24 | call to source | stl.cpp:142:7:142:8 | cs | |
| stl.cpp:140:17:140:18 | cs | stl.cpp:140:17:140:19 | call to basic_string | TAINT |
| stl.cpp:140:17:140:19 | call to basic_string | stl.cpp:143:7:143:8 | ss | |
| stl.cpp:148:19:148:24 | call to source | stl.cpp:151:17:151:18 | cs | |
| stl.cpp:151:17:151:18 | cs | stl.cpp:151:17:151:19 | call to basic_string | TAINT |
| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:154:7:154:8 | ss | |
| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:157:7:157:8 | ss | |
| stl.cpp:154:7:154:8 | ss | stl.cpp:154:10:154:14 | call to c_str | TAINT |
| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:154:2:154:16 | ... = ... | |
| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:156:7:156:8 | cs | |
| stl.cpp:163:18:163:24 | hello | stl.cpp:163:18:163:25 | call to basic_string | TAINT |
| stl.cpp:163:18:163:25 | call to basic_string | stl.cpp:168:8:168:9 | s1 | |
| stl.cpp:164:19:164:26 | call to basic_string | stl.cpp:169:8:169:9 | s2 | |
| stl.cpp:164:20:164:26 | hello | stl.cpp:164:19:164:26 | call to basic_string | TAINT |
| stl.cpp:166:8:166:14 | call to basic_string | stl.cpp:166:3:166:14 | ... = ... | |
| stl.cpp:166:8:166:14 | call to basic_string | stl.cpp:170:8:170:9 | s3 | |
| stl.cpp:166:8:166:14 | hello | stl.cpp:166:8:166:14 | call to basic_string | TAINT |
| stl.cpp:174:18:174:23 | call to source | stl.cpp:174:18:174:26 | call to basic_string | TAINT |
| stl.cpp:174:18:174:26 | call to basic_string | stl.cpp:179:8:179:9 | s1 | |
| stl.cpp:175:19:175:27 | call to basic_string | stl.cpp:180:8:180:9 | s2 | |
| stl.cpp:175:20:175:25 | call to source | stl.cpp:175:19:175:27 | call to basic_string | TAINT |
| stl.cpp:177:8:177:13 | call to source | stl.cpp:177:8:177:15 | call to basic_string | TAINT |
| stl.cpp:177:8:177:15 | call to basic_string | stl.cpp:177:3:177:15 | ... = ... | |
| stl.cpp:177:8:177:15 | call to basic_string | stl.cpp:181:8:181:9 | s3 | |
| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:186:20:186:21 | s1 | |
| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:188:8:188:9 | s1 | |
| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:190:8:190:9 | s1 | |
| stl.cpp:186:20:186:21 | s1 | stl.cpp:191:8:191:9 | s2 | |
| stl.cpp:188:8:188:9 | s1 | stl.cpp:188:3:188:9 | ... = ... | |
| stl.cpp:188:8:188:9 | s1 | stl.cpp:192:8:192:9 | s3 | |
| stl.cpp:196:19:196:40 | call to basic_string | stl.cpp:200:8:200:9 | s1 | |
| stl.cpp:196:32:196:37 | call to source | stl.cpp:196:19:196:40 | call to basic_string | TAINT |
| stl.cpp:198:8:198:28 | call to basic_string | stl.cpp:198:3:198:28 | ... = ... | |
| stl.cpp:198:8:198:28 | call to basic_string | stl.cpp:201:8:201:9 | s2 | |
| stl.cpp:198:20:198:25 | call to source | stl.cpp:198:8:198:28 | call to basic_string | TAINT |
| string.cpp:24:12:24:17 | call to source | string.cpp:28:7:28:7 | a | |
| string.cpp:25:16:25:20 | 123 | string.cpp:25:16:25:21 | call to basic_string | TAINT |
| string.cpp:25:16:25:21 | call to basic_string | string.cpp:29:7:29:7 | b | |
| string.cpp:25:16:25:21 | call to basic_string | string.cpp:31:7:31:7 | b | |
| string.cpp:26:16:26:21 | call to source | string.cpp:26:16:26:24 | call to basic_string | TAINT |
| string.cpp:26:16:26:24 | call to basic_string | string.cpp:30:7:30:7 | c | |
| string.cpp:26:16:26:24 | call to basic_string | string.cpp:32:7:32:7 | c | |
| string.cpp:31:7:31:7 | b | string.cpp:31:9:31:13 | call to c_str | TAINT |
| string.cpp:32:7:32:7 | c | string.cpp:32:9:32:13 | call to c_str | TAINT |
| string.cpp:37:16:37:28 | call to basic_string | string.cpp:38:7:38:11 | path1 | |
| string.cpp:37:17:37:26 | call to user_input | string.cpp:37:16:37:28 | call to basic_string | TAINT |
| string.cpp:38:7:38:11 | path1 | string.cpp:38:13:38:17 | call to c_str | TAINT |
| string.cpp:41:10:41:19 | call to user_input | string.cpp:41:10:41:21 | call to basic_string | TAINT |
| string.cpp:41:10:41:21 | call to basic_string | string.cpp:41:2:41:21 | ... = ... | |
| string.cpp:41:10:41:21 | call to basic_string | string.cpp:42:7:42:11 | path2 | |
| string.cpp:42:7:42:11 | path2 | string.cpp:42:13:42:17 | call to c_str | TAINT |
| string.cpp:44:15:44:24 | call to user_input | string.cpp:44:15:44:27 | call to basic_string | TAINT |
| string.cpp:44:15:44:27 | call to basic_string | string.cpp:45:7:45:11 | path3 | |
| string.cpp:45:7:45:11 | path3 | string.cpp:45:13:45:17 | call to c_str | TAINT |
| string.cpp:50:19:50:24 | call to source | string.cpp:53:17:53:18 | cs | |
| string.cpp:50:19:50:24 | call to source | string.cpp:55:7:55:8 | cs | |
| string.cpp:53:17:53:18 | cs | string.cpp:53:17:53:19 | call to basic_string | TAINT |
| string.cpp:53:17:53:19 | call to basic_string | string.cpp:56:7:56:8 | ss | |
| string.cpp:61:19:61:24 | call to source | string.cpp:64:17:64:18 | cs | |
| string.cpp:64:17:64:18 | cs | string.cpp:64:17:64:19 | call to basic_string | TAINT |
| string.cpp:64:17:64:19 | call to basic_string | string.cpp:67:7:67:8 | ss | |
| string.cpp:64:17:64:19 | call to basic_string | string.cpp:70:7:70:8 | ss | |
| string.cpp:67:7:67:8 | ss | string.cpp:67:10:67:14 | call to c_str | TAINT |
| string.cpp:67:10:67:14 | call to c_str | string.cpp:67:2:67:16 | ... = ... | |
| string.cpp:67:10:67:14 | call to c_str | string.cpp:69:7:69:8 | cs | |
| string.cpp:76:18:76:24 | hello | string.cpp:76:18:76:25 | call to basic_string | TAINT |
| string.cpp:76:18:76:25 | call to basic_string | string.cpp:81:8:81:9 | s1 | |
| string.cpp:77:19:77:26 | call to basic_string | string.cpp:82:8:82:9 | s2 | |
| string.cpp:77:20:77:26 | hello | string.cpp:77:19:77:26 | call to basic_string | TAINT |
| string.cpp:79:8:79:14 | call to basic_string | string.cpp:79:3:79:14 | ... = ... | |
| string.cpp:79:8:79:14 | call to basic_string | string.cpp:83:8:83:9 | s3 | |
| string.cpp:79:8:79:14 | hello | string.cpp:79:8:79:14 | call to basic_string | TAINT |
| string.cpp:87:18:87:23 | call to source | string.cpp:87:18:87:26 | call to basic_string | TAINT |
| string.cpp:87:18:87:26 | call to basic_string | string.cpp:92:8:92:9 | s1 | |
| string.cpp:88:19:88:27 | call to basic_string | string.cpp:93:8:93:9 | s2 | |
| string.cpp:88:20:88:25 | call to source | string.cpp:88:19:88:27 | call to basic_string | TAINT |
| string.cpp:90:8:90:13 | call to source | string.cpp:90:8:90:15 | call to basic_string | TAINT |
| string.cpp:90:8:90:15 | call to basic_string | string.cpp:90:3:90:15 | ... = ... | |
| string.cpp:90:8:90:15 | call to basic_string | string.cpp:94:8:94:9 | s3 | |
| string.cpp:98:15:98:16 | call to basic_string | string.cpp:99:20:99:21 | s1 | |
| string.cpp:98:15:98:16 | call to basic_string | string.cpp:101:8:101:9 | s1 | |
| string.cpp:98:15:98:16 | call to basic_string | string.cpp:103:8:103:9 | s1 | |
| string.cpp:99:20:99:21 | s1 | string.cpp:104:8:104:9 | s2 | |
| string.cpp:101:8:101:9 | s1 | string.cpp:101:3:101:9 | ... = ... | |
| string.cpp:101:8:101:9 | s1 | string.cpp:105:8:105:9 | s3 | |
| string.cpp:109:19:109:40 | call to basic_string | string.cpp:113:8:113:9 | s1 | |
| string.cpp:109:32:109:37 | call to source | string.cpp:109:19:109:40 | call to basic_string | TAINT |
| string.cpp:111:8:111:28 | call to basic_string | string.cpp:111:3:111:28 | ... = ... | |
| string.cpp:111:8:111:28 | call to basic_string | string.cpp:114:8:114:9 | s2 | |
| string.cpp:111:20:111:25 | call to source | string.cpp:111:8:111:28 | call to basic_string | TAINT |
| string.cpp:119:16:119:21 | call to source | string.cpp:119:16:119:24 | call to basic_string | TAINT |
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:120:15:120:15 | s | |
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:124:33:124:33 | s | |
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:124:50:124:50 | s | |
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:128:16:128:16 | s | |
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
| string.cpp:120:15:120:15 | call to end | string.cpp:120:15:120:15 | (__end) | |
| string.cpp:120:15:120:15 | call to operator* | string.cpp:121:8:121:8 | c | |
| string.cpp:120:15:120:15 | ref arg (__begin) | string.cpp:120:15:120:15 | (__begin) | |
| string.cpp:120:15:120:15 | ref arg (__begin) | string.cpp:120:15:120:15 | (__begin) | |
| string.cpp:120:15:120:15 | ref arg (__begin) | string.cpp:120:15:120:15 | (__begin) | |
| string.cpp:120:15:120:15 | ref arg (__range) | string.cpp:120:15:120:15 | (__range) | |
| string.cpp:120:15:120:15 | s | string.cpp:120:15:120:15 | (__range) | |
| string.cpp:120:15:120:15 | s | string.cpp:120:15:120:15 | (__range) | |
| string.cpp:120:15:120:15 | s | string.cpp:120:15:120:15 | call to operator* | TAINT |
| string.cpp:124:33:124:33 | ref arg s | string.cpp:124:50:124:50 | s | |
| string.cpp:124:33:124:33 | ref arg s | string.cpp:128:16:128:16 | s | |
| string.cpp:124:35:124:39 | call to begin | string.cpp:124:44:124:45 | it | |
| string.cpp:124:35:124:39 | call to begin | string.cpp:124:61:124:62 | it | |
| string.cpp:124:35:124:39 | call to begin | string.cpp:125:9:125:10 | it | |
| string.cpp:124:50:124:50 | ref arg s | string.cpp:124:50:124:50 | s | |
| string.cpp:124:50:124:50 | ref arg s | string.cpp:128:16:128:16 | s | |
| string.cpp:124:61:124:62 | ref arg it | string.cpp:124:44:124:45 | it | |
| string.cpp:124:61:124:62 | ref arg it | string.cpp:124:61:124:62 | it | |
| string.cpp:124:61:124:62 | ref arg it | string.cpp:125:9:125:10 | it | |
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
| string.cpp:128:16:128:16 | call to end | string.cpp:128:16:128:16 | (__end) | |
| string.cpp:128:16:128:16 | call to operator* | string.cpp:129:8:129:8 | c | |
| string.cpp:128:16:128:16 | ref arg (__begin) | string.cpp:128:16:128:16 | (__begin) | |
| string.cpp:128:16:128:16 | ref arg (__begin) | string.cpp:128:16:128:16 | (__begin) | |
| string.cpp:128:16:128:16 | ref arg (__begin) | string.cpp:128:16:128:16 | (__begin) | |
| string.cpp:128:16:128:16 | ref arg (__range) | string.cpp:128:16:128:16 | (__range) | |
| string.cpp:128:16:128:16 | s | string.cpp:128:16:128:16 | (__range) | |
| string.cpp:128:16:128:16 | s | string.cpp:128:16:128:16 | (__range) | |
| string.cpp:128:16:128:16 | s | string.cpp:128:16:128:16 | call to operator* | TAINT |
| string.cpp:132:28:132:33 | call to source | string.cpp:132:28:132:36 | call to basic_string | TAINT |
| string.cpp:132:28:132:36 | call to basic_string | string.cpp:133:22:133:28 | const_s | |
| string.cpp:133:22:133:22 | call to begin | string.cpp:133:22:133:22 | (__begin) | |
| string.cpp:133:22:133:22 | call to begin | string.cpp:133:22:133:22 | (__begin) | |
| string.cpp:133:22:133:22 | call to begin | string.cpp:133:22:133:22 | (__begin) | |
| string.cpp:133:22:133:22 | call to end | string.cpp:133:22:133:22 | (__end) | |
| string.cpp:133:22:133:22 | call to operator* | string.cpp:134:8:134:8 | c | |
| string.cpp:133:22:133:22 | ref arg (__begin) | string.cpp:133:22:133:22 | (__begin) | |
| string.cpp:133:22:133:22 | ref arg (__begin) | string.cpp:133:22:133:22 | (__begin) | |
| string.cpp:133:22:133:22 | ref arg (__begin) | string.cpp:133:22:133:22 | (__begin) | |
| string.cpp:133:22:133:28 | const_s | string.cpp:133:22:133:22 | (__range) | |
| string.cpp:133:22:133:28 | const_s | string.cpp:133:22:133:22 | (__range) | |
| string.cpp:133:22:133:28 | const_s | string.cpp:133:22:133:22 | call to operator* | TAINT |
| string.cpp:140:18:140:24 | hello | string.cpp:140:18:140:25 | call to basic_string | TAINT |
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:143:8:143:9 | s1 | |
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:143:13:143:14 | s1 | |
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:144:8:144:9 | s1 | |
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:145:13:145:14 | s1 | |
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:148:8:148:9 | s1 | |
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:149:8:149:9 | s1 | |
| string.cpp:141:18:141:23 | call to source | string.cpp:141:18:141:26 | call to basic_string | TAINT |
| string.cpp:141:18:141:26 | call to basic_string | string.cpp:144:13:144:14 | s2 | |
| string.cpp:141:18:141:26 | call to basic_string | string.cpp:145:8:145:9 | s2 | |
| string.cpp:141:18:141:26 | call to basic_string | string.cpp:146:8:146:9 | s2 | |
| string.cpp:141:18:141:26 | call to basic_string | string.cpp:146:13:146:14 | s2 | |
| string.cpp:143:8:143:9 | s1 | string.cpp:143:11:143:11 | call to operator+ | TAINT |
| string.cpp:143:13:143:14 | s1 | string.cpp:143:11:143:11 | call to operator+ | TAINT |
| string.cpp:144:8:144:9 | s1 | string.cpp:144:11:144:11 | call to operator+ | TAINT |
| string.cpp:144:13:144:14 | s2 | string.cpp:144:11:144:11 | call to operator+ | TAINT |
| string.cpp:145:8:145:9 | s2 | string.cpp:145:11:145:11 | call to operator+ | TAINT |
| string.cpp:145:13:145:14 | s1 | string.cpp:145:11:145:11 | call to operator+ | TAINT |
| string.cpp:146:8:146:9 | s2 | string.cpp:146:11:146:11 | call to operator+ | TAINT |
| string.cpp:146:13:146:14 | s2 | string.cpp:146:11:146:11 | call to operator+ | TAINT |
| string.cpp:148:8:148:9 | s1 | string.cpp:148:11:148:11 | call to operator+ | TAINT |
| string.cpp:148:13:148:20 | world | string.cpp:148:11:148:11 | call to operator+ | TAINT |
| string.cpp:149:8:149:9 | s1 | string.cpp:149:11:149:11 | call to operator+ | TAINT |
| string.cpp:149:13:149:18 | call to source | string.cpp:149:11:149:11 | call to operator+ | TAINT |
| string.cpp:153:18:153:22 | abc | string.cpp:153:18:153:23 | call to basic_string | TAINT |
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:157:8:157:9 | s3 | |
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:160:8:160:9 | s3 | |
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:164:8:164:9 | s3 | |
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:169:8:169:9 | s3 | |
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:173:8:173:9 | s3 | |
| string.cpp:154:18:154:23 | call to source | string.cpp:154:18:154:26 | call to basic_string | TAINT |
| string.cpp:154:18:154:26 | call to basic_string | string.cpp:157:13:157:14 | s4 | |
| string.cpp:154:18:154:26 | call to basic_string | string.cpp:161:9:161:10 | s4 | |
| string.cpp:154:18:154:26 | call to basic_string | string.cpp:170:13:170:14 | s4 | |
| string.cpp:157:8:157:9 | s3 | string.cpp:157:11:157:11 | call to operator+ | TAINT |
| string.cpp:157:11:157:11 | call to operator+ | string.cpp:157:3:157:14 | ... = ... | |
| string.cpp:157:11:157:11 | call to operator+ | string.cpp:158:8:158:9 | s5 | |
| string.cpp:157:13:157:14 | s4 | string.cpp:157:11:157:11 | call to operator+ | TAINT |
| string.cpp:160:8:160:9 | s3 | string.cpp:160:3:160:9 | ... = ... | |
| string.cpp:160:8:160:9 | s3 | string.cpp:161:3:161:4 | s6 | |
| string.cpp:160:8:160:9 | s3 | string.cpp:162:8:162:9 | s6 | |
| string.cpp:161:3:161:4 | ref arg s6 | string.cpp:162:8:162:9 | s6 | |
| string.cpp:161:9:161:10 | s4 | string.cpp:161:3:161:4 | ref arg s6 | TAINT |
| string.cpp:161:9:161:10 | s4 | string.cpp:161:6:161:6 | call to operator+= | TAINT |
| string.cpp:164:8:164:9 | s3 | string.cpp:164:3:164:9 | ... = ... | |
| string.cpp:164:8:164:9 | s3 | string.cpp:165:3:165:4 | s7 | |
| string.cpp:164:8:164:9 | s3 | string.cpp:166:3:166:4 | s7 | |
| string.cpp:164:8:164:9 | s3 | string.cpp:167:8:167:9 | s7 | |
| string.cpp:165:3:165:4 | ref arg s7 | string.cpp:166:3:166:4 | s7 | |
| string.cpp:165:3:165:4 | ref arg s7 | string.cpp:167:8:167:9 | s7 | |
| string.cpp:165:9:165:14 | call to source | string.cpp:165:3:165:4 | ref arg s7 | TAINT |
| string.cpp:165:9:165:14 | call to source | string.cpp:165:6:165:6 | call to operator+= | TAINT |
| string.cpp:166:3:166:4 | ref arg s7 | string.cpp:167:8:167:9 | s7 | |
| string.cpp:166:9:166:11 | | string.cpp:166:3:166:4 | ref arg s7 | TAINT |
| string.cpp:166:9:166:11 | | string.cpp:166:6:166:6 | call to operator+= | TAINT |
| string.cpp:169:8:169:9 | s3 | string.cpp:169:3:169:9 | ... = ... | |
| string.cpp:169:8:169:9 | s3 | string.cpp:170:3:170:4 | s8 | |
| string.cpp:169:8:169:9 | s3 | string.cpp:171:8:171:9 | s8 | |
| string.cpp:170:3:170:4 | ref arg s8 | string.cpp:171:8:171:9 | s8 | |
| string.cpp:170:13:170:14 | s4 | string.cpp:170:3:170:4 | ref arg s8 | TAINT |
| string.cpp:170:13:170:14 | s4 | string.cpp:170:6:170:11 | call to append | TAINT |
| string.cpp:173:8:173:9 | s3 | string.cpp:173:3:173:9 | ... = ... | |
| string.cpp:173:8:173:9 | s3 | string.cpp:174:3:174:4 | s9 | |
| string.cpp:173:8:173:9 | s3 | string.cpp:175:3:175:4 | s9 | |
| string.cpp:173:8:173:9 | s3 | string.cpp:176:8:176:9 | s9 | |
| string.cpp:174:3:174:4 | ref arg s9 | string.cpp:175:3:175:4 | s9 | |
| string.cpp:174:3:174:4 | ref arg s9 | string.cpp:176:8:176:9 | s9 | |
| string.cpp:174:13:174:18 | call to source | string.cpp:174:3:174:4 | ref arg s9 | TAINT |
| string.cpp:174:13:174:18 | call to source | string.cpp:174:6:174:11 | call to append | TAINT |
| string.cpp:175:3:175:4 | ref arg s9 | string.cpp:176:8:176:9 | s9 | |
| string.cpp:175:13:175:15 | | string.cpp:175:3:175:4 | ref arg s9 | TAINT |
| string.cpp:175:13:175:15 | | string.cpp:175:6:175:11 | call to append | TAINT |
| string.cpp:180:19:180:23 | abc | string.cpp:180:19:180:24 | call to basic_string | TAINT |
| string.cpp:180:19:180:24 | call to basic_string | string.cpp:183:3:183:5 | s10 | |
| string.cpp:180:19:180:24 | call to basic_string | string.cpp:184:8:184:10 | s10 | |
| string.cpp:181:12:181:26 | call to source | string.cpp:183:17:183:17 | c | |
| string.cpp:183:3:183:5 | ref arg s10 | string.cpp:184:8:184:10 | s10 | |
| string.cpp:183:17:183:17 | c | string.cpp:183:3:183:5 | ref arg s10 | TAINT |
| string.cpp:183:17:183:17 | c | string.cpp:183:7:183:12 | call to append | TAINT |
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:16:2:16:4 | ss1 | |
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:22:7:22:9 | ss1 | |
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:27:7:27:9 | ss1 | |
| stringstream.cpp:13:25:13:27 | call to basic_stringstream | stringstream.cpp:17:2:17:4 | ss2 | |
| stringstream.cpp:13:25:13:27 | call to basic_stringstream | stringstream.cpp:23:7:23:9 | ss2 | |
| stringstream.cpp:13:25:13:27 | call to basic_stringstream | stringstream.cpp:28:7:28:9 | ss2 | |
| stringstream.cpp:13:30:13:32 | call to basic_stringstream | stringstream.cpp:18:2:18:4 | ss3 | |
| stringstream.cpp:13:30:13:32 | call to basic_stringstream | stringstream.cpp:24:7:24:9 | ss3 | |
| stringstream.cpp:13:30:13:32 | call to basic_stringstream | stringstream.cpp:29:7:29:9 | ss3 | |
| stringstream.cpp:13:35:13:37 | call to basic_stringstream | stringstream.cpp:19:2:19:4 | ss4 | |
| stringstream.cpp:13:35:13:37 | call to basic_stringstream | stringstream.cpp:25:7:25:9 | ss4 | |
| stringstream.cpp:13:35:13:37 | call to basic_stringstream | stringstream.cpp:30:7:30:9 | ss4 | |
| stringstream.cpp:13:40:13:42 | call to basic_stringstream | stringstream.cpp:20:2:20:4 | ss5 | |
| stringstream.cpp:13:40:13:42 | call to basic_stringstream | stringstream.cpp:26:7:26:9 | ss5 | |
| stringstream.cpp:13:40:13:42 | call to basic_stringstream | stringstream.cpp:31:7:31:9 | ss5 | |
| stringstream.cpp:14:16:14:21 | call to source | stringstream.cpp:14:16:14:24 | call to basic_string | TAINT |
| stringstream.cpp:14:16:14:24 | call to basic_string | stringstream.cpp:20:9:20:9 | t | |
| stringstream.cpp:16:2:16:4 | ref arg ss1 | stringstream.cpp:22:7:22:9 | ss1 | |
| stringstream.cpp:16:2:16:4 | ref arg ss1 | stringstream.cpp:27:7:27:9 | ss1 | |
| stringstream.cpp:17:2:17:4 | ref arg ss2 | stringstream.cpp:23:7:23:9 | ss2 | |
| stringstream.cpp:17:2:17:4 | ref arg ss2 | stringstream.cpp:28:7:28:9 | ss2 | |
| stringstream.cpp:18:2:18:4 | ref arg ss3 | stringstream.cpp:24:7:24:9 | ss3 | |
| stringstream.cpp:18:2:18:4 | ref arg ss3 | stringstream.cpp:29:7:29:9 | ss3 | |
| stringstream.cpp:19:2:19:4 | ref arg ss4 | stringstream.cpp:25:7:25:9 | ss4 | |
| stringstream.cpp:19:2:19:4 | ref arg ss4 | stringstream.cpp:30:7:30:9 | ss4 | |
| stringstream.cpp:20:2:20:4 | ref arg ss5 | stringstream.cpp:26:7:26:9 | ss5 | |
| stringstream.cpp:20:2:20:4 | ref arg ss5 | stringstream.cpp:31:7:31:9 | ss5 | |
| stringstream.cpp:34:32:34:37 | source | stringstream.cpp:39:9:39:14 | source | |
| stringstream.cpp:36:20:36:22 | call to basic_stringstream | stringstream.cpp:38:2:38:4 | ss1 | |
| stringstream.cpp:36:20:36:22 | call to basic_stringstream | stringstream.cpp:41:7:41:9 | ss1 | |
| stringstream.cpp:36:20:36:22 | call to basic_stringstream | stringstream.cpp:43:7:43:9 | ss1 | |
| stringstream.cpp:36:25:36:27 | call to basic_stringstream | stringstream.cpp:39:2:39:4 | ss2 | |
| stringstream.cpp:36:25:36:27 | call to basic_stringstream | stringstream.cpp:42:7:42:9 | ss2 | |
| stringstream.cpp:36:25:36:27 | call to basic_stringstream | stringstream.cpp:44:7:44:9 | ss2 | |
| stringstream.cpp:38:2:38:4 | ref arg ss1 | stringstream.cpp:41:7:41:9 | ss1 | |
| stringstream.cpp:38:2:38:4 | ref arg ss1 | stringstream.cpp:43:7:43:9 | ss1 | |
| stringstream.cpp:39:2:39:4 | ref arg ss2 | stringstream.cpp:42:7:42:9 | ss2 | |
| stringstream.cpp:39:2:39:4 | ref arg ss2 | stringstream.cpp:44:7:44:9 | ss2 | |
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |
@@ -1199,3 +1330,57 @@
| taint.cpp:483:18:483:19 | ref arg & ... | taint.cpp:483:19:483:19 | n [inner post update] | |
| taint.cpp:483:19:483:19 | n | taint.cpp:483:18:483:19 | & ... | |
| taint.cpp:483:28:483:34 | source1 | taint.cpp:483:11:483:15 | ref arg & ... | TAINT |
| vector.cpp:8:43:8:49 | source1 | vector.cpp:12:21:12:27 | source1 | |
| vector.cpp:8:43:8:49 | source1 | vector.cpp:26:33:26:39 | source1 | |
| vector.cpp:12:21:12:27 | source1 | vector.cpp:12:21:12:28 | call to vector | TAINT |
| vector.cpp:12:21:12:28 | call to vector | vector.cpp:14:14:14:14 | v | |
| vector.cpp:12:21:12:28 | call to vector | vector.cpp:18:38:18:38 | v | |
| vector.cpp:12:21:12:28 | call to vector | vector.cpp:18:55:18:55 | v | |
| vector.cpp:12:21:12:28 | call to vector | vector.cpp:22:15:22:15 | v | |
| vector.cpp:14:14:14:14 | call to begin | vector.cpp:14:14:14:14 | (__begin) | |
| vector.cpp:14:14:14:14 | call to begin | vector.cpp:14:14:14:14 | (__begin) | |
| vector.cpp:14:14:14:14 | call to begin | vector.cpp:14:14:14:14 | (__begin) | |
| vector.cpp:14:14:14:14 | call to end | vector.cpp:14:14:14:14 | (__end) | |
| vector.cpp:14:14:14:14 | call to operator* | vector.cpp:15:8:15:8 | x | |
| vector.cpp:14:14:14:14 | ref arg (__begin) | vector.cpp:14:14:14:14 | (__begin) | |
| vector.cpp:14:14:14:14 | ref arg (__begin) | vector.cpp:14:14:14:14 | (__begin) | |
| vector.cpp:14:14:14:14 | ref arg (__begin) | vector.cpp:14:14:14:14 | (__begin) | |
| vector.cpp:14:14:14:14 | ref arg (__range) | vector.cpp:14:14:14:14 | (__range) | |
| vector.cpp:14:14:14:14 | v | vector.cpp:14:14:14:14 | (__range) | |
| vector.cpp:14:14:14:14 | v | vector.cpp:14:14:14:14 | (__range) | |
| vector.cpp:14:14:14:14 | v | vector.cpp:14:14:14:14 | call to operator* | TAINT |
| vector.cpp:18:38:18:38 | ref arg v | vector.cpp:18:55:18:55 | v | |
| vector.cpp:18:38:18:38 | ref arg v | vector.cpp:22:15:22:15 | v | |
| vector.cpp:18:40:18:44 | call to begin | vector.cpp:18:49:18:50 | it | |
| vector.cpp:18:40:18:44 | call to begin | vector.cpp:18:66:18:67 | it | |
| vector.cpp:18:40:18:44 | call to begin | vector.cpp:19:9:19:10 | it | |
| vector.cpp:18:55:18:55 | ref arg v | vector.cpp:18:55:18:55 | v | |
| vector.cpp:18:55:18:55 | ref arg v | vector.cpp:22:15:22:15 | v | |
| vector.cpp:18:66:18:67 | ref arg it | vector.cpp:18:49:18:50 | it | |
| vector.cpp:18:66:18:67 | ref arg it | vector.cpp:18:66:18:67 | it | |
| vector.cpp:18:66:18:67 | ref arg it | vector.cpp:19:9:19:10 | it | |
| vector.cpp:22:15:22:15 | call to begin | vector.cpp:22:15:22:15 | (__begin) | |
| vector.cpp:22:15:22:15 | call to begin | vector.cpp:22:15:22:15 | (__begin) | |
| vector.cpp:22:15:22:15 | call to begin | vector.cpp:22:15:22:15 | (__begin) | |
| vector.cpp:22:15:22:15 | call to end | vector.cpp:22:15:22:15 | (__end) | |
| vector.cpp:22:15:22:15 | call to operator* | vector.cpp:23:8:23:8 | x | |
| vector.cpp:22:15:22:15 | ref arg (__begin) | vector.cpp:22:15:22:15 | (__begin) | |
| vector.cpp:22:15:22:15 | ref arg (__begin) | vector.cpp:22:15:22:15 | (__begin) | |
| vector.cpp:22:15:22:15 | ref arg (__begin) | vector.cpp:22:15:22:15 | (__begin) | |
| vector.cpp:22:15:22:15 | ref arg (__range) | vector.cpp:22:15:22:15 | (__range) | |
| vector.cpp:22:15:22:15 | v | vector.cpp:22:15:22:15 | (__range) | |
| vector.cpp:22:15:22:15 | v | vector.cpp:22:15:22:15 | (__range) | |
| vector.cpp:22:15:22:15 | v | vector.cpp:22:15:22:15 | call to operator* | TAINT |
| vector.cpp:26:33:26:39 | source1 | vector.cpp:26:33:26:40 | call to vector | TAINT |
| vector.cpp:26:33:26:40 | call to vector | vector.cpp:27:21:27:27 | const_v | |
| vector.cpp:27:21:27:21 | call to begin | vector.cpp:27:21:27:21 | (__begin) | |
| vector.cpp:27:21:27:21 | call to begin | vector.cpp:27:21:27:21 | (__begin) | |
| vector.cpp:27:21:27:21 | call to begin | vector.cpp:27:21:27:21 | (__begin) | |
| vector.cpp:27:21:27:21 | call to end | vector.cpp:27:21:27:21 | (__end) | |
| vector.cpp:27:21:27:21 | call to operator* | vector.cpp:28:8:28:8 | x | |
| vector.cpp:27:21:27:21 | ref arg (__begin) | vector.cpp:27:21:27:21 | (__begin) | |
| vector.cpp:27:21:27:21 | ref arg (__begin) | vector.cpp:27:21:27:21 | (__begin) | |
| vector.cpp:27:21:27:21 | ref arg (__begin) | vector.cpp:27:21:27:21 | (__begin) | |
| vector.cpp:27:21:27:27 | const_v | vector.cpp:27:21:27:21 | (__range) | |
| vector.cpp:27:21:27:27 | const_v | vector.cpp:27:21:27:21 | (__range) | |
| vector.cpp:27:21:27:27 | const_v | vector.cpp:27:21:27:21 | call to operator* | TAINT |

View File

@@ -1,204 +0,0 @@
typedef unsigned long size_t;
namespace std
{
template<class charT> struct char_traits;
typedef size_t streamsize;
template <class T> class allocator {
public:
allocator() throw();
};
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
class basic_string {
public:
explicit basic_string(const Allocator& a = Allocator());
basic_string(const charT* s, const Allocator& a = Allocator());
const charT* c_str() const;
};
typedef basic_string<char> string;
template <class charT, class traits = char_traits<charT> >
class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
basic_istream<charT,traits>& operator>>(int& n);
};
template <class charT, class traits = char_traits<charT> >
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
typedef charT char_type;
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
basic_ostream<charT, traits>& operator<<(int n);
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT, traits, Allocator>& str);
template<class charT, class traits = char_traits<charT>>
class basic_iostream : public basic_istream<charT, traits>, public basic_ostream<charT, traits> {
public:
};
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
class basic_stringstream : public basic_iostream<charT, traits> {
public:
explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/);
basic_string<charT, traits, Allocator> str() const;
};
using stringstream = basic_stringstream<char>;
}
char *source();
void sink(const char *s) {};
void sink(const std::string &s) {};
void sink(const std::stringstream &s) {};
void test_string()
{
char *a = source();
std::string b("123");
std::string c(source());
sink(a); // tainted
sink(b);
sink(c); // tainted
sink(b.c_str());
sink(c.c_str()); // tainted
}
void test_stringstream()
{
std::stringstream ss1, ss2, ss3, ss4, ss5;
std::string t(source());
ss1 << "1234";
ss2 << source();
ss3 << "123" << source();
ss4 << source() << "456";
ss5 << t;
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss3); // tainted [NOT DETECTED]
sink(ss4); // tainted [NOT DETECTED]
sink(ss5); // tainted [NOT DETECTED]
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
sink(ss3.str()); // tainted [NOT DETECTED]
sink(ss4.str()); // tainted [NOT DETECTED]
sink(ss5.str()); // tainted [NOT DETECTED]
}
void test_stringstream_int(int source)
{
std::stringstream ss1, ss2;
ss1 << 1234;
ss2 << source;
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
}
using namespace std;
char *user_input() {
return source();
}
void sink(const char *filename, const char *mode);
void test_strings2()
{
string path1 = user_input();
sink(path1.c_str(), "r"); // tainted
string path2;
path2 = user_input();
sink(path2.c_str(), "r"); // tainted
string path3(user_input());
sink(path3.c_str(), "r"); // tainted
}
void test_string3()
{
const char *cs = source();
// convert char * -> std::string
std::string ss(cs);
sink(cs); // tainted
sink(ss); // tainted
}
void test_string4()
{
const char *cs = source();
// convert char * -> std::string
std::string ss(cs);
// convert back std::string -> char *
cs = ss.c_str();
sink(cs); // tainted
sink(ss); // tainted
}
void test_string_constructors_assignments()
{
{
std::string s1("hello");
std::string s2 = "hello";
std::string s3;
s3 = "hello";
sink(s1);
sink(s2);
sink(s3);
}
{
std::string s1(source());
std::string s2 = source();
std::string s3;
s3 = source();
sink(s1); // tainted
sink(s2); // tainted
sink(s3); // tainted
}
{
std::string s1;
std::string s2 = s1;
std::string s3;
s3 = s1;
sink(s1);
sink(s2);
sink(s3);
}
{
std::string s1 = std::string(source());
std::string s2;
s2 = std::string(source());
sink(s1); // tainted
sink(s2); // tainted
}
}

View File

@@ -0,0 +1,126 @@
typedef unsigned long size_t;
// --- string ---
namespace std
{
template<class charT> struct char_traits;
typedef size_t streamsize;
struct ptrdiff_t;
template <class iterator_category,
class value_type,
class difference_type = ptrdiff_t,
class pointer_type = value_type*,
class reference_type = value_type&>
struct iterator {
iterator &operator++();
iterator operator++(int);
bool operator==(iterator other) const;
bool operator!=(iterator other) const;
reference_type operator*() const;
};
struct input_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
template <class T> class allocator {
public:
allocator() throw();
typedef size_t size_type;
};
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
class basic_string {
public:
typedef typename Allocator::size_type size_type;
explicit basic_string(const Allocator& a = Allocator());
basic_string(const charT* s, const Allocator& a = Allocator());
const charT* c_str() const;
typedef std::iterator<random_access_iterator_tag, charT> iterator;
typedef std::iterator<random_access_iterator_tag, const charT> const_iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
const_iterator cbegin() const;
const_iterator cend() const;
template<class T> basic_string& operator+=(const T& t);
basic_string& operator+=(const charT* s);
basic_string& append(const basic_string& str);
basic_string& append(const charT* s);
basic_string& append(size_type n, charT c);
};
template<class charT, class traits, class Allocator> basic_string<charT, traits, Allocator> operator+(const basic_string<charT, traits, Allocator>& lhs, const basic_string<charT, traits, Allocator>& rhs);
template<class charT, class traits, class Allocator> basic_string<charT, traits, Allocator> operator+(const basic_string<charT, traits, Allocator>& lhs, const charT* rhs);
typedef basic_string<char> string;
template <class charT, class traits = char_traits<charT> >
class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
basic_istream<charT,traits>& operator>>(int& n);
};
template <class charT, class traits = char_traits<charT> >
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
typedef charT char_type;
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
basic_ostream<charT, traits>& operator<<(int n);
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT, traits, Allocator>& str);
template<class charT, class traits = char_traits<charT>>
class basic_iostream : public basic_istream<charT, traits>, public basic_ostream<charT, traits> {
public:
};
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
class basic_stringstream : public basic_iostream<charT, traits> {
public:
explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/);
basic_string<charT, traits, Allocator> str() const;
};
using stringstream = basic_stringstream<char>;
}
// --- vector ---
namespace std {
template <class T>
class vector {
private:
void *data_;
public:
vector(int size);
T& operator[](int idx);
const T& operator[](int idx) const;
typedef std::iterator<random_access_iterator_tag, T> iterator;
typedef std::iterator<random_access_iterator_tag, const T> const_iterator;
iterator begin() noexcept;
iterator end() noexcept;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
};
}

View File

@@ -0,0 +1,186 @@
#include "stl.h"
using namespace std;
char *source();
namespace ns_char
{
char source();
}
char *user_input() {
return source();
}
void sink(const char *s) {};
void sink(const std::string &s) {};
void sink(const char *filename, const char *mode);
void sink(char) {}
void test_string()
{
char *a = source();
std::string b("123");
std::string c(source());
sink(a); // tainted
sink(b);
sink(c); // tainted
sink(b.c_str());
sink(c.c_str()); // tainted
}
void test_strings2()
{
string path1 = user_input();
sink(path1.c_str(), "r"); // tainted
string path2;
path2 = user_input();
sink(path2.c_str(), "r"); // tainted
string path3(user_input());
sink(path3.c_str(), "r"); // tainted
}
void test_string3()
{
const char *cs = source();
// convert char * -> std::string
std::string ss(cs);
sink(cs); // tainted
sink(ss); // tainted
}
void test_string4()
{
const char *cs = source();
// convert char * -> std::string
std::string ss(cs);
// convert back std::string -> char *
cs = ss.c_str();
sink(cs); // tainted
sink(ss); // tainted
}
void test_string_constructors_assignments()
{
{
std::string s1("hello");
std::string s2 = "hello";
std::string s3;
s3 = "hello";
sink(s1);
sink(s2);
sink(s3);
}
{
std::string s1(source());
std::string s2 = source();
std::string s3;
s3 = source();
sink(s1); // tainted
sink(s2); // tainted
sink(s3); // tainted
}
{
std::string s1;
std::string s2 = s1;
std::string s3;
s3 = s1;
sink(s1);
sink(s2);
sink(s3);
}
{
std::string s1 = std::string(source());
std::string s2;
s2 = std::string(source());
sink(s1); // tainted
sink(s2); // tainted
}
}
void test_range_based_for_loop_string() {
std::string s(source());
for(char c : s) {
sink(c); // tainted [NOT DETECTED by IR]
}
for(std::string::iterator it = s.begin(); it != s.end(); ++it) {
sink(*it); // tainted [NOT DETECTED]
}
for(char& c : s) {
sink(c); // tainted [NOT DETECTED by IR]
}
const std::string const_s(source());
for(const char& c : const_s) {
sink(c); // tainted [NOT DETECTED by IR]
}
}
void test_string_append() {
{
std::string s1("hello");
std::string s2(source());
sink(s1 + s1);
sink(s1 + s2); // tainted
sink(s2 + s1); // tainted
sink(s2 + s2); // tainted
sink(s1 + " world");
sink(s1 + source()); // tainted
}
{
std::string s3("abc");
std::string s4(source());
std::string s5, s6, s7, s8, s9;
s5 = s3 + s4;
sink(s5); // tainted
s6 = s3;
s6 += s4;
sink(s6); // tainted
s7 = s3;
s7 += source();
s7 += " ";
sink(s7); // tainted
s8 = s3;
s8.append(s4);
sink(s8); // tainted
s9 = s3;
s9.append(source());
s9.append(" ");
sink(s9); // tainted
}
{
std::string s10("abc");
char c = ns_char::source();
s10.append(1, c);
sink(s10); // tainted
}
}

View File

@@ -0,0 +1,45 @@
#include "stl.h"
using namespace std;
char *source();
void sink(const std::string &s) {};
void sink(const std::stringstream &s) {};
void test_stringstream()
{
std::stringstream ss1, ss2, ss3, ss4, ss5;
std::string t(source());
ss1 << "1234";
ss2 << source();
ss3 << "123" << source();
ss4 << source() << "456";
ss5 << t;
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss3); // tainted [NOT DETECTED]
sink(ss4); // tainted [NOT DETECTED]
sink(ss5); // tainted [NOT DETECTED]
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
sink(ss3.str()); // tainted [NOT DETECTED]
sink(ss4.str()); // tainted [NOT DETECTED]
sink(ss5.str()); // tainted [NOT DETECTED]
}
void test_stringstream_int(int source)
{
std::stringstream ss1, ss2;
ss1 << 1234;
ss2 << source;
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
}

View File

@@ -32,21 +32,34 @@
| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source |
| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source |
| movableclass.cpp:65:11:65:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source |
| stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source |
| stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source |
| stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source |
| stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
| stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
| stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source |
| stl.cpp:143:7:143:8 | ss | stl.cpp:137:19:137:24 | call to source |
| stl.cpp:156:7:156:8 | cs | stl.cpp:148:19:148:24 | call to source |
| stl.cpp:157:7:157:8 | ss | stl.cpp:148:19:148:24 | call to source |
| stl.cpp:179:8:179:9 | s1 | stl.cpp:174:18:174:23 | call to source |
| stl.cpp:180:8:180:9 | s2 | stl.cpp:175:20:175:25 | call to source |
| stl.cpp:181:8:181:9 | s3 | stl.cpp:177:8:177:13 | call to source |
| stl.cpp:200:8:200:9 | s1 | stl.cpp:196:32:196:37 | call to source |
| stl.cpp:201:8:201:9 | s2 | stl.cpp:198:20:198:25 | call to source |
| string.cpp:28:7:28:7 | a | string.cpp:24:12:24:17 | call to source |
| string.cpp:30:7:30:7 | c | string.cpp:26:16:26:21 | call to source |
| string.cpp:32:9:32:13 | call to c_str | string.cpp:26:16:26:21 | call to source |
| string.cpp:38:13:38:17 | call to c_str | string.cpp:14:10:14:15 | call to source |
| string.cpp:42:13:42:17 | call to c_str | string.cpp:14:10:14:15 | call to source |
| string.cpp:45:13:45:17 | call to c_str | string.cpp:14:10:14:15 | call to source |
| string.cpp:55:7:55:8 | cs | string.cpp:50:19:50:24 | call to source |
| string.cpp:56:7:56:8 | ss | string.cpp:50:19:50:24 | call to source |
| string.cpp:69:7:69:8 | cs | string.cpp:61:19:61:24 | call to source |
| string.cpp:70:7:70:8 | ss | string.cpp:61:19:61:24 | call to source |
| string.cpp:92:8:92:9 | s1 | string.cpp:87:18:87:23 | call to source |
| string.cpp:93:8:93:9 | s2 | string.cpp:88:20:88:25 | call to source |
| string.cpp:94:8:94:9 | s3 | string.cpp:90:8:90:13 | call to source |
| string.cpp:113:8:113:9 | s1 | string.cpp:109:32:109:37 | call to source |
| string.cpp:114:8:114:9 | s2 | string.cpp:111:20:111:25 | call to source |
| string.cpp:121:8:121:8 | c | string.cpp:119:16:119:21 | call to source |
| string.cpp:129:8:129:8 | c | string.cpp:119:16:119:21 | call to source |
| string.cpp:134:8:134:8 | c | string.cpp:132:28:132:33 | call to source |
| string.cpp:144:11:144:11 | call to operator+ | string.cpp:141:18:141:23 | call to source |
| string.cpp:145:11:145:11 | call to operator+ | string.cpp:141:18:141:23 | call to source |
| string.cpp:146:11:146:11 | call to operator+ | string.cpp:141:18:141:23 | call to source |
| string.cpp:149:11:149:11 | call to operator+ | string.cpp:149:13:149:18 | call to source |
| string.cpp:158:8:158:9 | s5 | string.cpp:154:18:154:23 | call to source |
| string.cpp:162:8:162:9 | s6 | string.cpp:154:18:154:23 | call to source |
| string.cpp:167:8:167:9 | s7 | string.cpp:165:9:165:14 | call to source |
| string.cpp:171:8:171:9 | s8 | string.cpp:154:18:154:23 | call to source |
| string.cpp:176:8:176:9 | s9 | string.cpp:174:13:174:18 | call to source |
| string.cpp:184:8:184:10 | s10 | string.cpp:181:12:181:26 | call to source |
| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source |
| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source |
| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source |
@@ -153,3 +166,6 @@
| taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source |
| taint.cpp:471:7:471:7 | y | taint.cpp:462:6:462:11 | call to source |
| taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 |
| vector.cpp:15:8:15:8 | x | vector.cpp:8:43:8:49 | source1 |
| vector.cpp:23:8:23:8 | x | vector.cpp:8:43:8:49 | source1 |
| vector.cpp:28:8:28:8 | x | vector.cpp:8:43:8:49 | source1 |

View File

@@ -30,20 +30,33 @@
| movableclass.cpp:55:8:55:9 | movableclass.cpp:52:23:52:28 | AST only |
| movableclass.cpp:64:8:64:9 | movableclass.cpp:23:55:23:60 | AST only |
| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only |
| stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only |
| stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only |
| stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only |
| stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only |
| stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only |
| stl.cpp:142:7:142:8 | stl.cpp:137:19:137:26 | IR only |
| stl.cpp:143:7:143:8 | stl.cpp:137:19:137:24 | AST only |
| stl.cpp:156:7:156:8 | stl.cpp:148:19:148:24 | AST only |
| stl.cpp:157:7:157:8 | stl.cpp:148:19:148:24 | AST only |
| stl.cpp:179:8:179:9 | stl.cpp:174:18:174:23 | AST only |
| stl.cpp:180:8:180:9 | stl.cpp:175:20:175:25 | AST only |
| stl.cpp:181:8:181:9 | stl.cpp:177:8:177:13 | AST only |
| stl.cpp:200:8:200:9 | stl.cpp:196:32:196:37 | AST only |
| stl.cpp:201:8:201:9 | stl.cpp:198:20:198:25 | AST only |
| string.cpp:30:7:30:7 | string.cpp:26:16:26:21 | AST only |
| string.cpp:32:9:32:13 | string.cpp:26:16:26:21 | AST only |
| string.cpp:38:13:38:17 | string.cpp:14:10:14:15 | AST only |
| string.cpp:42:13:42:17 | string.cpp:14:10:14:15 | AST only |
| string.cpp:45:13:45:17 | string.cpp:14:10:14:15 | AST only |
| string.cpp:55:7:55:8 | string.cpp:50:19:50:26 | IR only |
| string.cpp:56:7:56:8 | string.cpp:50:19:50:24 | AST only |
| string.cpp:69:7:69:8 | string.cpp:61:19:61:24 | AST only |
| string.cpp:70:7:70:8 | string.cpp:61:19:61:24 | AST only |
| string.cpp:92:8:92:9 | string.cpp:87:18:87:23 | AST only |
| string.cpp:93:8:93:9 | string.cpp:88:20:88:25 | AST only |
| string.cpp:94:8:94:9 | string.cpp:90:8:90:13 | AST only |
| string.cpp:113:8:113:9 | string.cpp:109:32:109:37 | AST only |
| string.cpp:114:8:114:9 | string.cpp:111:20:111:25 | AST only |
| string.cpp:121:8:121:8 | string.cpp:119:16:119:21 | AST only |
| string.cpp:129:8:129:8 | string.cpp:119:16:119:21 | AST only |
| string.cpp:134:8:134:8 | string.cpp:132:28:132:33 | AST only |
| string.cpp:144:11:144:11 | string.cpp:141:18:141:23 | AST only |
| string.cpp:145:11:145:11 | string.cpp:141:18:141:23 | AST only |
| string.cpp:146:11:146:11 | string.cpp:141:18:141:23 | AST only |
| string.cpp:149:11:149:11 | string.cpp:149:13:149:18 | AST only |
| string.cpp:158:8:158:9 | string.cpp:154:18:154:23 | AST only |
| string.cpp:162:8:162:9 | string.cpp:154:18:154:23 | AST only |
| string.cpp:167:8:167:9 | string.cpp:165:9:165:14 | AST only |
| string.cpp:171:8:171:9 | string.cpp:154:18:154:23 | AST only |
| string.cpp:176:8:176:9 | string.cpp:174:13:174:18 | AST only |
| string.cpp:184:8:184:10 | string.cpp:181:12:181:26 | AST only |
| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only |
| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only |
| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only |
@@ -88,3 +101,6 @@
| taint.cpp:446:7:446:7 | taint.cpp:445:14:445:28 | AST only |
| taint.cpp:447:9:447:17 | taint.cpp:445:14:445:28 | AST only |
| taint.cpp:471:7:471:7 | taint.cpp:462:6:462:11 | AST only |
| vector.cpp:15:8:15:8 | vector.cpp:8:43:8:49 | AST only |
| vector.cpp:23:8:23:8 | vector.cpp:8:43:8:49 | AST only |
| vector.cpp:28:8:28:8 | vector.cpp:8:43:8:49 | AST only |

View File

@@ -1,10 +1,10 @@
| format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | call to source |
| format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source |
| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source |
| stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source |
| stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source |
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source |
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:26 | (const char *)... |
| string.cpp:28:7:28:7 | (const char *)... | string.cpp:24:12:24:17 | call to source |
| string.cpp:28:7:28:7 | a | string.cpp:24:12:24:17 | call to source |
| string.cpp:55:7:55:8 | cs | string.cpp:50:19:50:24 | call to source |
| string.cpp:55:7:55:8 | cs | string.cpp:50:19:50:26 | (const char *)... |
| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | call to source |
| structlikeclass.cpp:61:8:61:9 | s2 | structlikeclass.cpp:58:24:58:29 | call to source |
| structlikeclass.cpp:62:8:62:20 | ... = ... | structlikeclass.cpp:62:13:62:18 | call to source |

View File

@@ -0,0 +1,30 @@
#include "stl.h"
using namespace std;
void sink(int);
void test_range_based_for_loop_vector(int source1) {
// Tainting the vector by allocating a tainted length. This doesn't represent
// how a vector would typically get tainted, but it allows this test to avoid
// being concerned with std::vector modeling.
std::vector<int> v(source1);
for(int x : v) {
sink(x); // tainted [NOT DETECTED by IR]
}
for(std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
sink(*it); // tainted [NOT DETECTED]
}
for(int& x : v) {
sink(x); // tainted [NOT DETECTED by IR]
}
const std::vector<int> const_v(source1);
for(const int& x : const_v) {
sink(x); // tainted [NOT DETECTED by IR]
}
}

View File

@@ -20,7 +20,7 @@
| functions.cpp:23:7:23:11 | Table | Class | functions.cpp:30:8:30:13 | insert | |
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:33:7:33:7 | operator= | |
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:36:2:36:8 | MyClass | Constructor, NoArgConstructor, getAConstructor() |
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:37:2:37:8 | MyClass | Constructor, ConversionConstructor, getAConstructor() |
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:37:2:37:8 | MyClass | Constructor, getAConstructor() |
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:38:2:38:8 | MyClass | Constructor, CopyConstructor, getAConstructor() |
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:39:2:39:8 | MyClass | Constructor, ConversionConstructor, MoveConstructor, getAConstructor() |
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:39:2:39:8 | MyClass | Constructor, MoveConstructor, getAConstructor() |
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:40:2:40:13 | operator int | ConversionOperator |

View File

@@ -19,9 +19,6 @@ string describe(Class c, MemberFunction f) {
f instanceof Destructor and
result = "Destructor"
or
f instanceof ConversionConstructor and
result = "ConversionConstructor"
or
f instanceof CopyConstructor and
result = "CopyConstructor"
or

View File

@@ -1,4 +1,4 @@
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
from VariableAccess expr
select expr, lowerBound(expr)
select expr, lowerBound(expr).toString()

View File

@@ -463,3 +463,30 @@ int test_unsigned_mult02(unsigned b) {
return total;
}
unsigned long mult_rounding() {
unsigned long x, y, xy;
x = y = 1000000003UL; // 1e9 + 3
xy = x * y;
return xy; // BUG: upper bound should be >= 1000000006000000009UL
}
unsigned long mult_overflow() {
unsigned long x, y, xy;
x = 274177UL;
y = 67280421310721UL;
xy = x * y;
return xy; // BUG: lower bound should be <= 18446744073709551617UL
}
unsigned long mult_lower_bound(unsigned int ui, unsigned long ul) {
if (ui >= 10) {
unsigned long result = (unsigned long)ui * ui;
return result; // BUG: upper bound should be >= 18446744065119617025 (possibly a pretty-printing bug)
}
if (ul >= 10) {
unsigned long result = ul * ul;
return result; // lower bound is correctly 0 (overflow is possible)
}
return 0;
}

View File

@@ -1,4 +1,4 @@
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
from VariableAccess expr
select expr, upperBound(expr)
select expr, upperBound(expr).toString()

View File

@@ -385,10 +385,39 @@ void bitwise_ands()
void unsigned_mult(unsigned int x, unsigned int y) {
if(x < 13 && y < 35) {
if(x * y > 1024) {} // always false [NOT DETECTED]
if(x * y > 1024) {} // always false
if(x * y < 204) {}
if(x >= 3 && y >= 2) {
if(x * y < 5) {} // always false [NOT DETECTED]
if(x * y < 5) {} // always false
}
}
}
}
void mult_rounding() {
unsigned long x, y, xy;
x = y = 1000000003UL; // 1e9 + 3
xy = 1000000006000000009UL; // x * y, precisely
// Even though the range analysis wrongly considers x*y to be xy - 9, there
// are no PointlessComparison false positives in these tests because alerts
// are suppressed when ulp() < 1, which roughly means that the number is
// larger than 2^53.
if (x * y < xy) {} // always false [NOT DETECTED]
if (x * y > xy) {} // always false [NOT DETECTED]
}
void mult_overflow() {
unsigned long x, y;
// The following two numbers multiply to 2^64 + 1, which is 1 when truncated
// to 64-bit unsigned.
x = 274177UL;
y = 67280421310721UL;
if (x * y == 1) {} // always true [BUG: reported as always false]
// This bug appears to be caused by
// `RangeAnalysisUtils::typeUpperBound(unsigned long)` having a result of
// 2**64 + 384, making the range analysis think that the multiplication can't
// overflow. The correct `typeUpperBound` would be 2**64 - 1, but we can't
// represent that with a QL float or int. We could make `typeUpperBound`
// exclusive instead of inclusive, but there is no exclusive upper bound for
// floats.
}

View File

@@ -41,6 +41,9 @@
| PointlessComparison.c:372:6:372:16 | ... >= ... | Comparison is always true because ... >> ... >= 1. |
| PointlessComparison.c:373:6:373:16 | ... >= ... | Comparison is always false because ... >> ... <= 1. |
| PointlessComparison.c:383:6:383:17 | ... >= ... | Comparison is always false because ... & ... <= 2. |
| PointlessComparison.c:388:10:388:21 | ... > ... | Comparison is always false because ... * ... <= 408. |
| PointlessComparison.c:391:12:391:20 | ... < ... | Comparison is always false because ... * ... >= 6. |
| PointlessComparison.c:414:7:414:16 | ... == ... | Comparison is always false because ... * ... >= 18446744073709552000. |
| PointlessComparison.cpp:36:6:36:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854776000. |
| PointlessComparison.cpp:41:6:41:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. |
| PointlessComparison.cpp:42:6:42:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. |

View File

@@ -177,4 +177,43 @@ void FalseNegativeTestCases()
for (int i = 100; i > 0; i += 2) {}
// For comparison
for (int i = 100; i > 0; i ++ ) {} // BUG
}
}
void IntendedOverflow(unsigned char p)
{
const unsigned char m = 10;
unsigned char i;
signed char s;
for (i = 63; i < 64; i--) {} // GOOD (legitimate way to count down with an unsigned)
for (i = 63; i < 128; i--) {} // DUBIOUS (could still be a typo?)
for (i = 63; i < 255; i--) {} // GOOD
for (i = m - 1; i < m; i--) {} // GOOD
for (i = m - 2; i < m; i--) {} // DUBIOUS
for (i = m; i < m + 1; i--) {} // GOOD
for (s = 63; s < 64; s--) {} // BAD (signed numbers don't wrap at 0 / at all)
for (s = m + 1; s < m; s--) {} // BAD (never runs)
for (i = p - 1; i < p; i--) {} // GOOD
for (s = p - 1; s < p; s--) {} // BAD [NOT DETECTED]
{
int n;
n = 64;
for (i = n - 1; i < n; i--) {} // GOOD
n = 64;
for (i = n - 1; i < 64; i--) {} // GOOD
n = 64;
for (i = 63; i < n; i--) {} // GOOD
n = 64;
for (s = n - 1; s < n; s--) {} // BAD [NOT DETECTED]
n = 64;
for (s = n - 1; s < 64; s--) {} // BAD
n = 64;
for (s = 63; s < n; s--) {} // BAD [NOT DETECTED]
}
}

View File

@@ -20,3 +20,6 @@
| inconsistentLoopDirection.cpp:140:5:142:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (200), but the terminal condition is lower (0). |
| inconsistentLoopDirection.cpp:175:5:175:36 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts downward from a value (0), but the terminal condition is higher (10). |
| inconsistentLoopDirection.cpp:179:5:179:38 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (100), but the terminal condition is lower (0). |
| inconsistentLoopDirection.cpp:196:5:196:32 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (63), but the terminal condition is higher (64). |
| inconsistentLoopDirection.cpp:197:5:197:34 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (... + ...), but the terminal condition is always false. |
| inconsistentLoopDirection.cpp:215:3:215:33 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (... - ...), but the terminal condition is higher (64). |

View File

@@ -0,0 +1,23 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>The <code>DataSet</code> and <code>DataTable</code> types are legacy .NET components that you can use to represent data sets as managed objects.</p>
<p>While <code>DataSet</code> and <code>DataTable</code> do impose default limitations on the types that are allowed to be present while deserializing XML payloads, <code>DataSet</code> and <code>DataTable</code> are in general not safe when populated with untrusted input.</p>
<p>Please visit <a href="https://go.microsoft.com/fwlink/?linkid=2132227">DataSet and DataTable security guidance</a> for more details.</p>
</overview>
<recommendation>
<p>Please review the <a href="https://go.microsoft.com/fwlink/?linkid=2132227">DataSet and DataTable security guidance</a> before making use of these types for serialization.</p>
</recommendation>
<references>
<li>Microsoft Docs<a href="https://go.microsoft.com/fwlink/?linkid=2132227">DataSet and DataTable security guidance</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,100 @@
/**
* Provides classes for `DataSet` or `DataTable` deserialization queries.
*
* Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.
*/
import csharp
/**
* Abstract class that depends or inherits from `DataSet` or `DataTable` types.
*/
abstract class DataSetOrTableRelatedClass extends Class { }
/**
* `DataSet`, `DataTable` types, or any types derived from them.
*/
class DataSetOrTable extends DataSetOrTableRelatedClass {
DataSetOrTable() {
this.getABaseType*().getQualifiedName() = "System.Data.DataTable" or
this.getABaseType*().getQualifiedName() = "System.Data.DataSet"
}
}
/**
* A Class that include a property or generic collection of type `DataSet` and `DataTable`
*/
class ClassWithDataSetOrTableMember extends DataSetOrTableRelatedClass {
ClassWithDataSetOrTableMember() {
this.getAMember().(AssignableMember).getType() instanceof DataSetOrTable
or
exists(Property p | p = this.getAProperty() |
p.getType() instanceof DataSetOrTable or
p.getType().(ConstructedGeneric).getATypeArgument() instanceof DataSetOrTable
)
}
}
/**
* Serializable types
*/
class SerializableClass extends Class {
SerializableClass() {
(
this.getABaseType*().getQualifiedName() = "System.Xml.Serialization.XmlSerializer" or
this.getABaseType*().getQualifiedName() = "System.Runtime.Serialization.ISerializable" or
this.getABaseType*().getQualifiedName() = "System.Runtime.Serialization.XmlObjectSerializer" or
this.getABaseType*().getQualifiedName() =
"System.Runtime.Serialization.ISerializationSurrogateProvider" or
this.getABaseType*().getQualifiedName() =
"System.Runtime.Serialization.XmlSerializableServices" or
this.getABaseType*().getQualifiedName() = "System.Xml.Serialization.IXmlSerializable"
)
or
exists(Attribute a | a = this.getAnAttribute() |
a.getType().getQualifiedName() = "System.SerializableAttribute"
)
}
}
/**
* Holds if the serializable class `c` has a property or field `m` that is of `DataSet` or `DataTable` related type
*/
predicate isClassUnsafeXmlSerializerImplementation(SerializableClass c, AssignableMember am) {
am = c.getAMember() and
am.getType() instanceof DataSetOrTableRelatedClass
}
/**
* Serializable class that has a property or field that is of `DataSet` or `DataTable` related type
*/
class UnsafeXmlSerializerImplementation extends SerializableClass {
UnsafeXmlSerializerImplementation() { isClassUnsafeXmlSerializerImplementation(this, _) }
}
/**
* Method that may be unsafe when used to deserialize DataSet and DataTable related types
*/
class UnsafeXmlReadMethod extends Method {
UnsafeXmlReadMethod() {
this.getQualifiedName() = "System.Data.DataTable.ReadXml"
or
this.getQualifiedName() = "System.Data.DataTable.ReadXmlSchema"
or
this.getQualifiedName() = "System.Data.DataSet.ReadXml"
or
this.getQualifiedName() = "System.Data.DataSet.ReadXmlSchema"
or
this.getName().matches("ReadXml%") and
exists(Class c | c.getAMethod() = this |
c.getABaseType*() instanceof DataSetOrTableRelatedClass
)
}
}
/**
* MethodCall that may be unsafe when used to deserialize DataSet and DataTable related types
*/
class UnsafeXmlReadMethodCall extends MethodCall {
UnsafeXmlReadMethodCall() { exists(UnsafeXmlReadMethod uxrm | uxrm.getACall() = this) }
}

View File

@@ -0,0 +1,5 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="DataSetSerialization.qhelp" /></qhelp>

View File

@@ -0,0 +1,16 @@
/**
* @name Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types
* @description Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types may lead to the usage of dangerous functionality. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.
* @kind problem
* @problem.severity warning
* @id cs/dataset-serialization/defining-dataset-related-type
* @tags security
*/
import csharp
import DataSetSerialization
from DataSetOrTableRelatedClass dstc
where dstc.fromSource()
select dstc,
"Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."

View File

@@ -0,0 +1,5 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="DataSetSerialization.qhelp" /></qhelp>

View File

@@ -0,0 +1,20 @@
/**
* @name Defining a potentially unsafe XML serializer
* @description Defining an XML serializable class that includes members that derive from DataSet or DataTable type may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.
* @kind problem
* @problem.severity error
* @precision medium
* @id cs/dataset-serialization/defining-potentially-unsafe-xml-serializer
* @tags security
*/
import csharp
import DataSetSerialization
from UnsafeXmlSerializerImplementation c, Member m
where
c.fromSource() and
isClassUnsafeXmlSerializerImplementation(c, m)
select m,
"Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.",
c, c.toString(), m, m.toString()

View File

@@ -0,0 +1,5 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="DataSetSerialization.qhelp" /></qhelp>

View File

@@ -0,0 +1,43 @@
/**
* @name Unsafe type is used in data contract serializer
* @description Unsafe type is used in data contract serializer. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."
* @kind problem
* @problem.severity error
* @precision medium
* @id cs/dataset-serialization/unsafe-type-used-data-contract-serializer
* @tags security
*/
import csharp
import DataSetSerialization
predicate xmlSerializerConstructorArgument(Expr e) {
exists(ObjectCreation oc, Constructor c | e = oc.getArgument(0) |
c = oc.getTarget() and
c.getDeclaringType().getABaseType*().hasQualifiedName("System.Xml.Serialization.XmlSerializer")
)
}
predicate unsafeDataContractTypeCreation(Expr e) {
exists(MethodCall gt |
gt.getTarget().getName() = "GetType" and
e = gt and
gt.getQualifier().getType() instanceof DataSetOrTableRelatedClass
)
or
e.(TypeofExpr).getTypeAccess().getTarget() instanceof DataSetOrTableRelatedClass
}
class Conf extends DataFlow::Configuration {
Conf() { this = "FlowToDataSerializerConstructor" }
override predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) }
override predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) }
}
from Conf conf, DataFlow::Node source, DataFlow::Node sink
where conf.hasFlow(source, sink)
select sink,
"Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source.",
source, source.toString()

View File

@@ -0,0 +1,5 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="DataSetSerialization.qhelp" /></qhelp>

View File

@@ -0,0 +1,16 @@
/**
* @name XML deserialization with a type type derived from DataSet or DataTable
* @description Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."
* @kind problem
* @problem.severity error
* @precision medium
* @id cs/dataset-serialization/xml-deserialization-with-dataset
* @tags security
*/
import csharp
import DataSetSerialization
from UnsafeXmlReadMethodCall mc
select mc,
"Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."

View File

@@ -0,0 +1,2 @@
| test0.cs:13:18:13:43 | DerivesFromDeprecatedType1 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
| test0.cs:59:18:59:38 | AttributeSerializer01 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |

View File

@@ -0,0 +1 @@
experimental/Security Features/Serialization/DefiningDatasetRelatedType.ql

View File

@@ -0,0 +1,2 @@
| test0.cs:15:24:15:32 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:13:18:13:43 | DerivesFromDeprecatedType1 | DerivesFromDeprecatedType1 | test0.cs:15:24:15:32 | MyDataSet | MyDataSet |
| test0.cs:61:25:61:33 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:59:18:59:38 | AttributeSerializer01 | AttributeSerializer01 | test0.cs:61:25:61:33 | MyDataSet | MyDataSet |

View File

@@ -0,0 +1 @@
experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql

View File

@@ -0,0 +1,2 @@
| test0.cs:95:49:95:63 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:95:49:95:63 | typeof(...) | typeof(...) |
| test0.cs:96:49:96:77 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:96:49:96:77 | typeof(...) | typeof(...) |

View File

@@ -0,0 +1 @@
experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.ql

View File

@@ -0,0 +1 @@
| test0.cs:88:17:88:46 | call to method ReadXmlSchema | Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |

View File

@@ -0,0 +1 @@
experimental/Security Features/Serialization/XmlDeserializationWithDataSet.ql

View File

@@ -0,0 +1,101 @@
// semmle-extractor-options: /r:System.Data.Common.dll /r:System.Runtime.WindowsRuntime.dll /r:System.Xml.XmlSerializer.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Collections.dll /r:System.Private.Xml.dll /r:System.Private.DataContractSerialization.dll /r:System.Runtime.Extensions.dll /r:System.ComponentModel.TypeConverter.dll /r:System.Xml.ReaderWriter.dll /r:System.IO.FileSystem.dll
using System;
using System.Data;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Xml;
using System.Collections.Generic;
namespace DataSetSerializationTest
{
public class DerivesFromDeprecatedType1 : XmlSerializer // warning:DefiningDatasetRelatedType.ql
{
public DataSet MyDataSet { get; set; } // bug:DefiningPotentiallyUnsafeXmlSerializer.ql
public DerivesFromDeprecatedType1()
{
}
}
/*
* TODO: I cannot use DataContract on a QL unit test
*
[DataContract(Name = "Customer", Namespace = "http://www.contoso.com")]
public class PatternDataContractSerializer : XmlObjectSerializer
{
[DataMember()]
public DataSet MyDataSet { get; set; }
[DataMember()]
public DataTable MyDataTable { get; set; }
PatternDataContractSerializer() { }
private ExtensionDataObject extensionData_Value;
public ExtensionDataObject ExtensionData
{
get
{
return extensionData_Value;
}
set
{
extensionData_Value = value;
}
}
public override void WriteObject(System.IO.Stream stream, object graph) { }
public override void WriteObjectContent(System.Xml.XmlDictionaryWriter writer, object graph) { }
public override bool IsStartObject(System.Xml.XmlDictionaryReader reader) { return false; }
public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, object graph) { }
public override void WriteEndObject(System.Xml.XmlWriter writer) { }
public override void WriteEndObject(XmlDictionaryWriter writer) { }
public override object ReadObject(System.IO.Stream stream) { return null; }
public override object ReadObject(XmlDictionaryReader reader, bool b) { return null; }
}
*/
[Serializable()]
public class AttributeSerializer01 // warning:DefiningDatasetRelatedType.ql
{
private DataSet MyDataSet; // bug:DefiningPotentiallyUnsafeXmlSerializer.ql
AttributeSerializer01()
{
}
}
class Program
{
static string GetSerializedDataSet(DataSet dataSet)
{
DataTable dataTable = new DataTable("MyTable");
dataTable.Columns.Add("FirstName", typeof(string));
dataTable.Columns.Add("LastName", typeof(string));
dataTable.Columns.Add("Age", typeof(int));
StringWriter writer = new StringWriter();
dataSet.WriteXml(writer, XmlWriteMode.DiffGram);
return writer.ToString();
}
static void datatable_readxmlschema_01(string fileName)
{
using (FileStream fs = File.OpenRead(fileName))
{
DataTable newTable = new DataTable();
System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(fs);
newTable.ReadXmlSchema(reader); //bug:XmlDeserializationWithDataSet.ql
}
}
static void Main(string[] args)
{
XmlSerializer x = new XmlSerializer(typeof(DataSet)); // bug:UnsafeTypeUsedDataContractSerializer.ql
XmlSerializer y = new XmlSerializer(typeof(AttributeSerializer01)); //bug:UnsafeTypeUsedDataContractSerializer.ql
Console.WriteLine("Hello World!");
}
}
}

View File

@@ -157,6 +157,8 @@ If your query is a security query, use one or more `@tags` to associate it with
When you tag a query like this, the associated CWE pages from [MITRE.org](http://cwe.mitre.org/index.html) will automatically appear in the reference section of its associated qhelp file.
Security relevant queries that will be run in Code Scanning should also have a `@security-severity` tag. See https://github.com/github/cwe-scores for more information about this tag.
## QL area
### Alert messages

View File

@@ -7,7 +7,6 @@
* @precision very-high
* @id java/integer-multiplication-cast-to-long
* @tags reliability
* security
* correctness
* types
* external/cwe/cwe-190

View File

@@ -0,0 +1,8 @@
public class XSS extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// BAD: a request parameter is written directly to an error response page
response.sendError(HttpServletResponse.SC_NOT_FOUND,
"The page \"" + request.getParameter("page") + "\" was not found.");
}
}

View File

@@ -0,0 +1,12 @@
public class SQLInjection extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
StringBuilder sqlQueryBuilder = new StringBuilder();
sqlQueryBuilder.append("SELECT * FROM user WHERE user_id='");
sqlQueryBuilder.append(request.getParameter("user_id"));
sqlQueryBuilder.append("'");
// ...
}
}

View File

@@ -0,0 +1,48 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Using unsanitized untrusted data in an external API can cause a variety of security issues. This query reports
all external APIs that are used with untrusted data, along with how frequently the API is used, and how many
unique sources of untrusted data flow to this API. This query is designed primarily to help identify which APIs
may be relevant for security analysis of this application.</p>
<p>An external API is defined as a method call to a method that is not defined in the source code, not overridden
in the source code, and is not modeled as a taint step in the default taint library. External APIs may be from the
Java standard library, third party dependencies or from internal dependencies. The query will report the method
signature with a fully qualified name, along with either <code>[param x]</code>, where <code>x</code> indicates the
position of the parameter receiving the untrusted data or <code>[qualifier]</code> indicating the untrusted data is
used as the qualifier to the method call.</p>
</overview>
<recommendation>
<p>For each result:</p>
<ul>
<li>If the result highlights a known sink, no action is required.</li>
<li>If the result highlights an unknown sink for a problem, then add modeling for the sink to the relevant query.</li>
<li>If the result represents a call to an external API which transfers taint, add the appropriate modeling, and
re-run the query to determine what new results have appeared due to this additional modeling.</li>
</ul>
<p>Otherwise, the result is likely uninteresting. Custom versions of this query can extend the <code>SafeExternalAPIMethod</code>
class to exclude known safe external APIs from future analysis.</p>
</recommendation>
<example>
<p>If the query were to return the API <code>javax.servlet.http.HttpServletResponse.sendError(int, java.lang.String) [param 1]</code>
then we should first consider whether this a security relevant sink. In this case, this is writing to a HTTP response, so we should
consider whether this is an XSS sink. If it is, we should confirm that it is handled by the XSS query.</p>
<p>If the query were to return the API <code>java.lang.StringBuilder.append(java.lang.String) [param 0]</code>, then this should be
reviewed as a possible taint step, because tainted data would flow from the 0th argument to the qualifier of the call.</p>
<p>Note that both examples are correctly handled by the standard taint tracking library and XSS query.</p>
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,18 @@
/**
* @name Frequency counts for external APIs that are used with untrusted data
* @description This reports the external APIs that are used with untrusted data, along with how
* frequently the API is called, and how many unique sources of untrusted data flow
* to it.
* @id java/count-untrusted-data-external-api
* @kind table
* @tags security external/cwe/cwe-20
*/
import java
import semmle.code.java.security.ExternalAPIs
import semmle.code.java.dataflow.DataFlow
from ExternalAPIUsedWithUntrustedData externalAPI
select externalAPI, count(externalAPI.getUntrustedDataNode()) as numberOfUses,
externalAPI.getNumberOfUntrustedSources() as numberOfUntrustedSources order by
numberOfUntrustedSources desc

View File

@@ -0,0 +1,57 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Using unsanitized untrusted data in an external API can cause a variety of security issues. This query reports
external APIs that use untrusted data. The results are not filtered so that you can audit all examples. The query provides data for security reviews of the application and you can also use it to identify external APIs that should be modeled as either taint steps, or sinks for specific problems.</p>
<p>An external API is defined as a method call to a method that is not defined in the source code, not overridden
in the source code, and is not modeled as a taint step in the default taint library. External APIs may be from the
Java standard library, third-party dependencies or from internal dependencies. The query reports uses of
untrusted data in either the qualifier or as one of the arguments of external APIs.</p>
</overview>
<recommendation>
<p>For each result:</p>
<ul>
<li>If the result highlights a known sink, confirm that the result is reported by the relevant query, or
that the result is a false positive because this data is sanitized.</li>
<li>If the result highlights an unknown sink for a problem, then add modeling for the sink to the relevant query,
and confirm that the result is either found, or is safe due to appropriate sanitization.</li>
<li>If the result represents a call to an external API that transfers taint, add the appropriate modeling, and
re-run the query to determine what new results have appeared due to this additional modeling.</li>
</ul>
<p>Otherwise, the result is likely uninteresting. Custom versions of this query can extend the <code>SafeExternalAPIMethod</code>
class to exclude known safe external APIs from future analysis.</p>
</recommendation>
<example>
<p>In this first example, a request parameter is read from <code>HttpServletRequest</code> and then ultimately used in a call to the
<code>HttpServletResponse.sendError</code> external API:</p>
<sample src="ExternalAPISinkExample.java" />
<p>This is an XSS sink. The XSS query should therefore be reviewed to confirm that this sink is appropriately modeled,
and if it is, to confirm that the query reports this particular result, or that the result is a false positive due to
some existing sanitization.</p>
<p>In this second example, again a request parameter is read from <code>HttpServletRequest</code>.</p>
<sample src="ExternalAPITaintStepExample.java" />
<p>If the query reported the call to <code>StringBuilder.append</code> on line 7, this would suggest that this external API is
not currently modeled as a taint step in the taint tracking library. The next step would be to model this as a taint step, then
re-run the query to determine what additional results might be found. In this example, it seems likely that the result of the
<code>StringBuilder</code> will be executed as an SQL query, potentially leading to an SQL injection vulnerability.</p>
<p>Note that both examples are correctly handled by the standard taint tracking library and XSS query.</p>
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,21 @@
/**
* @name Untrusted data passed to external API
* @description Data provided remotely is used in this external API without sanitization, which could be a security risk.
* @id java/untrusted-data-to-external-api
* @kind path-problem
* @precision low
* @problem.severity error
* @tags security external/cwe/cwe-20
*/
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.ExternalAPIs
import DataFlow::PathGraph
from UntrustedDataToExternalAPIConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink, source, sink,
"Call to " + sink.getNode().(ExternalAPIDataNode).getMethodDescription() +
" with untrusted data from $@.", source, source.toString()

View File

@@ -1,74 +0,0 @@
import java
import semmle.code.java.controlflow.Guards
abstract class PathCreation extends Expr {
abstract Expr getInput();
}
class PathsGet extends PathCreation, MethodAccess {
PathsGet() {
exists(Method m | m = this.getMethod() |
m.getDeclaringType() instanceof TypePaths and
m.getName() = "get"
)
}
override Expr getInput() { result = this.getAnArgument() }
}
class FileSystemGetPath extends PathCreation, MethodAccess {
FileSystemGetPath() {
exists(Method m | m = this.getMethod() |
m.getDeclaringType() instanceof TypeFileSystem and
m.getName() = "getPath"
)
}
override Expr getInput() { result = this.getAnArgument() }
}
class FileCreation extends PathCreation, ClassInstanceExpr {
FileCreation() { this.getConstructedType() instanceof TypeFile }
override Expr getInput() {
result = this.getAnArgument() and
// Relevant arguments include those that are not a `File`.
not result.getType() instanceof TypeFile
}
}
class FileWriterCreation extends PathCreation, ClassInstanceExpr {
FileWriterCreation() { this.getConstructedType().getQualifiedName() = "java.io.FileWriter" }
override Expr getInput() {
result = this.getAnArgument() and
// Relevant arguments are those of type `String`.
result.getType() instanceof TypeString
}
}
predicate inWeakCheck(Expr e) {
// None of these are sufficient to guarantee that a string is safe.
exists(MethodAccess m, Method def | m.getQualifier() = e and m.getMethod() = def |
def.getName() = "startsWith" or
def.getName() = "endsWith" or
def.getName() = "isEmpty" or
def.getName() = "equals"
)
or
// Checking against `null` has no bearing on path traversal.
exists(EqualityTest b | b.getAnOperand() = e | b.getAnOperand() instanceof NullLiteral)
}
// Ignore cases where the variable has been checked somehow,
// but allow some particularly obviously bad cases.
predicate guarded(VarAccess e) {
exists(PathCreation p | e = p.getInput()) and
exists(ConditionBlock cb, Expr c |
cb.getCondition().getAChildExpr*() = c and
c = e.getVariable().getAnAccess() and
cb.controls(e.getBasicBlock(), true) and
// Disallow a few obviously bad checks.
not inWeakCheck(c)
)
}

View File

@@ -14,8 +14,9 @@
import java
import semmle.code.java.dataflow.FlowSources
import PathsCommon
import semmle.code.java.security.PathCreation
import DataFlow::PathGraph
import TaintedPathCommon
class ContainsDotDotSanitizer extends DataFlow::BarrierGuard {
ContainsDotDotSanitizer() {
@@ -34,7 +35,7 @@ class TaintedPathConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
exists(Expr e | e = sink.asExpr() | e = any(PathCreation p).getInput() and not guarded(e))
exists(Expr e | e = sink.asExpr() | e = any(PathCreation p).getAnInput() and not guarded(e))
}
override predicate isSanitizer(DataFlow::Node node) {
@@ -48,7 +49,7 @@ class TaintedPathConfig extends TaintTracking::Configuration {
from DataFlow::PathNode source, DataFlow::PathNode sink, PathCreation p, TaintedPathConfig conf
where
sink.getNode().asExpr() = p.getInput() and
sink.getNode().asExpr() = p.getAnInput() and
conf.hasFlowPath(source, sink)
select p, source, sink, "$@ flows to here and is used in a path.", source.getNode(),
"User-provided value"

View File

@@ -0,0 +1,33 @@
/**
* Models a very basic guard for the tainted path queries.
*/
import java
import semmle.code.java.controlflow.Guards
import semmle.code.java.security.PathCreation
private predicate inWeakCheck(Expr e) {
// None of these are sufficient to guarantee that a string is safe.
exists(MethodAccess m, Method def | m.getQualifier() = e and m.getMethod() = def |
def.getName() = "startsWith" or
def.getName() = "endsWith" or
def.getName() = "isEmpty" or
def.getName() = "equals"
)
or
// Checking against `null` has no bearing on path traversal.
exists(EqualityTest b | b.getAnOperand() = e | b.getAnOperand() instanceof NullLiteral)
}
// Ignore cases where the variable has been checked somehow,
// but allow some particularly obviously bad cases.
predicate guarded(VarAccess e) {
exists(PathCreation p | e = p.getAnInput()) and
exists(ConditionBlock cb, Expr c |
cb.getCondition().getAChildExpr*() = c and
c = e.getVariable().getAnAccess() and
cb.controls(e.getBasicBlock(), true) and
// Disallow a few obviously bad checks.
not inWeakCheck(c)
)
}

View File

@@ -14,15 +14,18 @@
import java
import semmle.code.java.dataflow.FlowSources
import PathsCommon
import semmle.code.java.security.PathCreation
import DataFlow::PathGraph
import TaintedPathCommon
class TaintedPathLocalConfig extends TaintTracking::Configuration {
TaintedPathLocalConfig() { this = "TaintedPathLocalConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(PathCreation p).getInput() }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(PathCreation p).getAnInput()
}
}
from
@@ -30,7 +33,7 @@ from
TaintedPathLocalConfig conf
where
e = sink.getNode().asExpr() and
e = p.getInput() and
e = p.getAnInput() and
conf.hasFlowPath(source, sink) and
not guarded(e)
select p, source, sink, "$@ flows to here and is used in a path.", source.getNode(),

View File

@@ -1,10 +1,7 @@
import java
import semmle.code.java.dataflow.FlowSources
import DataFlow
import semmle.code.java.frameworks.Jndi
import semmle.code.java.frameworks.UnboundId
import semmle.code.java.frameworks.SpringLdap
import semmle.code.java.frameworks.ApacheLdap
import semmle.code.java.security.LdapInjection
/**
* A taint-tracking configuration for unvalidated user input that is used to construct LDAP queries.
@@ -16,391 +13,9 @@ class LdapInjectionFlowConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) { sink instanceof LdapInjectionSink }
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
}
override predicate isSanitizer(DataFlow::Node node) { node instanceof LdapInjectionSanitizer }
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
ldapNameStep(node1, node2) or
ldapNameAddAllStep(node1, node2) or
ldapNameGetCloneStep(node1, node2) or
filterStep(node1, node2) or
filterToStringStep(node1, node2) or
unboundIdSearchRequestStep(node1, node2) or
unboundIdSearchRequestDuplicateStep(node1, node2) or
unboundIdSearchRequestSetStep(node1, node2) or
ldapQueryStep(node1, node2) or
ldapQueryBaseStep(node1, node2) or
ldapQueryBuilderStep(node1, node2) or
hardcodedFilterStep(node1, node2) or
springLdapFilterToStringStep(node1, node2) or
ldapNameBuilderStep(node1, node2) or
ldapNameBuilderBuildStep(node1, node2) or
ldapUtilsStep(node1, node2) or
apacheSearchRequestStep(node1, node2) or
apacheSearchRequestGetStep(node1, node2) or
apacheLdapDnStep(node1, node2) or
apacheLdapDnGetStep(node1, node2)
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
any(LdapInjectionAdditionalTaintStep a).step(pred, succ)
}
}
/**
* JNDI sink for LDAP injection vulnerabilities, i.e. 1st (DN) or 2nd (filter) argument to
* `search` method from `DirContext`.
*/
predicate jndiLdapInjectionSinkMethod(Method m, int index) {
m.getDeclaringType().getAnAncestor() instanceof TypeDirContext and
m.hasName("search") and
index in [0 .. 1]
}
/**
* UnboundID sink for LDAP injection vulnerabilities,
* i.e. LDAPConnection.search, LDAPConnection.asyncSearch or LDAPConnection.searchForEntry method.
*/
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
)
}
/**
* Spring LDAP sink for LDAP injection vulnerabilities,
* i.e. LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method.
*/
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
)
}
/** Apache LDAP API sink for LDAP injection vulnerabilities, i.e. LdapConnection.search method. */
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")
)
}
/** Holds if parameter at index `index` in method `m` is LDAP injection sink. */
predicate ldapInjectionSinkMethod(Method m, int index) {
jndiLdapInjectionSinkMethod(m, index) or
unboundIdLdapInjectionSinkMethod(m, index) or
springLdapInjectionSinkMethod(m, index) or
apacheLdapInjectionSinkMethod(m, index)
}
/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
class LdapInjectionSink extends DataFlow::ExprNode {
LdapInjectionSink() {
exists(MethodAccess ma, Method m, int index |
ma.getMethod() = m and
ma.getArgument(index) = this.getExpr() and
ldapInjectionSinkMethod(m, index)
)
}
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `LdapName`,
* i.e. `new LdapName(tainted)`.
*/
predicate ldapNameStep(ExprNode n1, ExprNode n2) {
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeLdapName |
n1.asExpr() = cc.getAnArgument() and
n2.asExpr() = cc
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `List<Rdn>` and `LdapName`,
* i.e. `new LdapName().addAll(tainted)`.
*/
predicate ldapNameAddAllStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma |
n1.asExpr() = ma.getAnArgument() and
(n2.asExpr() = ma or n2.asExpr() = ma.getQualifier())
|
ma.getMethod() instanceof MethodLdapNameAddAll
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `LdapName` and `LdapName` or
* `String`, i.e. `taintedLdapName.clone()`, `taintedLdapName.getAll()`,
* `taintedLdapName.getRdns()` or `taintedLdapName.toString()`.
*/
predicate ldapNameGetCloneStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma and
ma.getMethod() = m
|
m instanceof MethodLdapNameClone or
m instanceof MethodLdapNameGetAll or
m instanceof MethodLdapNameGetRdns or
m instanceof MethodLdapNameToString
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and UnboundID `Filter`,
* i.e. `Filter.create*(tainted)`.
*/
predicate filterStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getAnArgument() and
n2.asExpr() = ma and
ma.getMethod() = m
|
m instanceof MethodUnboundIdFilterCreate or
m instanceof MethodUnboundIdFilterCreateANDFilter or
m instanceof MethodUnboundIdFilterCreateNOTFilter or
m instanceof MethodUnboundIdFilterCreateORFilter or
m instanceof MethodUnboundIdFilterSimplifyFilter
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between UnboundID `Filter` and `String`,
* i.e. `taintedFilter.toString()` or `taintedFilter.toString(buffer)`.
*/
predicate filterToStringStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
(n2.asExpr() = ma or n2.asExpr() = ma.getAnArgument())
|
ma.getMethod() = m and
m.getDeclaringType() instanceof TypeUnboundIdLdapFilter and
(m.hasName("toString") or m.hasName("toNormalizedString"))
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and UnboundID
* `SearchRequest`, i.e. `new SearchRequest(tainted)`.
*/
predicate unboundIdSearchRequestStep(ExprNode n1, ExprNode n2) {
exists(ConstructorCall cc, int index, Parameter param |
cc.getConstructedType() instanceof TypeUnboundIdSearchRequest
|
n1.asExpr() = cc.getArgument(index) and
n2.asExpr() = cc and
cc.getConstructor().getParameter(index) = param and
not param.isVarargs()
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between UnboundID `SearchRequest`
* and UnboundID `SearchRequest`, i.e. `taintedSearchRequest.duplicate()`.
*/
predicate unboundIdSearchRequestDuplicateStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m | n1.asExpr() = ma.getQualifier() and n2.asExpr() = ma |
ma.getMethod() = m and
m.getDeclaringType().getAnAncestor() instanceof TypeUnboundIdReadOnlySearchRequest and
m.hasName("duplicate")
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between DN or filter and UnboundID
* `SearchRequest`, i.e. `searchRequest.setBaseDN(tainted)` or `searchRequest.setFilter(tainted)`.
*/
predicate unboundIdSearchRequestSetStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getAnArgument() and
n2.asExpr() = ma.getQualifier() and
ma.getMethod() = m
|
m instanceof MethodUnboundIdSearchRequestSetBaseDN or
m instanceof MethodUnboundIdSearchRequestSetFilter
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Spring `LdapQuery`,
* i.e. `LdapQueryBuilder.query().filter(tainted)` or `LdapQueryBuilder.query().base(tainted)`.
*/
predicate ldapQueryStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m, int index |
n1.asExpr() = ma.getArgument(index) and
n2.asExpr() = ma and
ma.getMethod() = m and
index = 0
|
m instanceof MethodSpringLdapQueryBuilderFilter or
m instanceof MethodSpringLdapQueryBuilderBase
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Spring `LdapQueryBuilder` and
* `Name`, i.e. `taintedLdapQueryBuilder.base()`.
*/
predicate ldapQueryBaseStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma and
ma.getMethod() = m
|
m instanceof MethodSpringLdapQueryBuilderBase and
m.getNumberOfParameters() = 0
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Spring `LdapQueryBuilder`,
* `ConditionCriteria` or `ContainerCriteria`, i.e. when the query is built, for example
* `query().base(tainted).where("objectclass").is("person")`.
*/
predicate ldapQueryBuilderStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma and
ma.getMethod() = m
|
(
m.getDeclaringType() instanceof TypeSpringLdapQueryBuilder or
m.getDeclaringType() instanceof TypeSpringConditionCriteria or
m.getDeclaringType() instanceof TypeSpringContainerCriteria
) and
(
m.getReturnType() instanceof TypeSpringLdapQueryBuilder or
m.getReturnType() instanceof TypeSpringConditionCriteria or
m.getReturnType() instanceof TypeSpringContainerCriteria
)
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Spring
* `HardcodedFilter`, i.e. `new HardcodedFilter(tainted)`.
*/
predicate hardcodedFilterStep(ExprNode n1, ExprNode n2) {
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeSpringHardcodedFilter |
n1.asExpr() = cc.getAnArgument() and
n2.asExpr() = cc
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Spring `Filter` and
* `String`, i.e. `taintedFilter.toString()`, `taintedFilter.encode()` or
* `taintedFilter.encode(buffer)`.
*/
predicate springLdapFilterToStringStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
(n2.asExpr() = ma or n2.asExpr() = ma.getAnArgument()) and
ma.getMethod() = m
|
m.getDeclaringType().getAnAncestor() instanceof TypeSpringLdapFilter and
(m.hasName("encode") or m.hasName("toString"))
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Spring
* `LdapNameBuilder`, i.e. `LdapNameBuilder.newInstance(tainted)` or
* `LdapNameBuilder.newInstance().add(tainted)`.
*/
predicate ldapNameBuilderStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getAnArgument() and
(n2.asExpr() = ma or n2.asExpr() = ma.getQualifier()) and
ma.getMethod() = m and
m.getNumberOfParameters() = 1
|
m instanceof MethodSpringLdapNameBuilderNewInstance or
m instanceof MethodSpringLdapNameBuilderAdd
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between tainted Spring `LdapNameBuilder`
* and `LdapName`, `LdapNameBuilder.build()`.
*/
predicate ldapNameBuilderBuildStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma | n1.asExpr() = ma.getQualifier() and n2.asExpr() = ma |
ma.getMethod() instanceof MethodSpringLdapNameBuilderBuild
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `LdapName` via
* Spring `LdapUtils.newLdapName`, i.e. `LdapUtils.newLdapName(tainted)`.
*/
predicate ldapUtilsStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma | n1.asExpr() = ma.getAnArgument() and n2.asExpr() = ma |
ma.getMethod() instanceof MethodSpringLdapUtilsNewLdapName
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Apache LDAP API
* `SearchRequest`, i.e. `searchRequest.setFilter(tainted)` or `searchRequest.setBase(tainted)`.
*/
predicate apacheSearchRequestStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getAnArgument() and
n2.asExpr() = ma.getQualifier()
|
ma.getMethod() = m and
m.getDeclaringType().getAnAncestor() instanceof TypeApacheSearchRequest and
(m.hasName("setFilter") or m.hasName("setBase"))
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Apache LDAP API `SearchRequest`
* and filter or DN i.e. `tainterSearchRequest.getFilter()` or `taintedSearchRequest.getBase()`.
*/
predicate apacheSearchRequestGetStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m | n1.asExpr() = ma.getQualifier() and n2.asExpr() = ma |
ma.getMethod() = m and
m.getDeclaringType().getAnAncestor() instanceof TypeApacheSearchRequest and
(m.hasName("getFilter") or m.hasName("getBase"))
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Apache LDAP API
* `Dn`, i.e. `new Dn(tainted)`.
*/
predicate apacheLdapDnStep(ExprNode n1, ExprNode n2) {
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeApacheDn |
n1.asExpr() = cc.getAnArgument() and
n2.asExpr() = cc
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Apache LDAP API `Dn`
* and `String` i.e. `taintedDn.getName()`, `taintedDn.getNormName()` or `taintedDn.toString()`.
*/
predicate apacheLdapDnGetStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m | n1.asExpr() = ma.getQualifier() and n2.asExpr() = ma |
ma.getMethod() = m and
m.getDeclaringType().getAnAncestor() instanceof TypeApacheDn and
(m.hasName("getName") or m.hasName("getNormName") or m.hasName("toString"))
)
}

View File

@@ -11,7 +11,8 @@
*/
import java
import ResponseSplitting
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.ResponseSplitting
import DataFlow::PathGraph
class ResponseSplittingConfig extends TaintTracking::Configuration {
@@ -19,7 +20,7 @@ class ResponseSplittingConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource and
not source instanceof WhitelistedSource
not source instanceof SafeHeaderSplittingSource
}
override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }

View File

@@ -1,38 +0,0 @@
import java
import semmle.code.java.frameworks.Servlets
import semmle.code.java.dataflow.FlowSources
/**
* Header-splitting sinks. Expressions that end up in an HTTP header.
*/
class HeaderSplittingSink extends DataFlow::ExprNode {
HeaderSplittingSink() {
exists(ResponseAddCookieMethod m, MethodAccess ma |
ma.getMethod() = m and
this.getExpr() = ma.getArgument(0)
)
or
exists(ResponseAddHeaderMethod m, MethodAccess ma |
ma.getMethod() = m and
this.getExpr() = ma.getAnArgument()
)
or
exists(ResponseSetHeaderMethod m, MethodAccess ma |
ma.getMethod() = m and
this.getExpr() = ma.getAnArgument()
)
or
exists(JaxRsResponseBuilder builder, Method m |
m = builder.getAMethod() and m.getName() = "header"
|
this.getExpr() = m.getAReference().getArgument(1)
)
}
}
class WhitelistedSource extends DataFlow::ExprNode {
WhitelistedSource() {
this.asExpr().(MethodAccess).getMethod() instanceof HttpServletRequestGetHeaderMethod or
this.asExpr().(MethodAccess).getMethod() instanceof CookieGetNameMethod
}
}

View File

@@ -12,7 +12,7 @@
import java
import semmle.code.java.dataflow.FlowSources
import ResponseSplitting
import semmle.code.java.security.ResponseSplitting
import DataFlow::PathGraph
class ResponseSplittingLocalConfig extends TaintTracking::Configuration {

View File

@@ -22,7 +22,10 @@ import semmle.code.java.security.XSS
*/
class PrintStackTraceMethod extends Method {
PrintStackTraceMethod() {
getDeclaringType().hasQualifiedName("java.lang", "Throwable") and
getDeclaringType()
.getSourceDeclaration()
.getASourceSupertype*()
.hasQualifiedName("java.lang", "Throwable") and
getName() = "printStackTrace"
}
}
@@ -96,7 +99,8 @@ class StackTraceStringToXssSinkFlowConfig extends TaintTracking2::Configuration
*/
predicate printsStackExternally(MethodAccess call, Expr stackTrace) {
printsStackToWriter(call) and
call.getQualifier() = stackTrace
call.getQualifier() = stackTrace and
not call.getQualifier() instanceof SuperAccess
}
/**

View File

@@ -3,7 +3,7 @@
* @description Using broken or weak cryptographic algorithms can allow an attacker to compromise security.
* @kind path-problem
* @problem.severity warning
* @precision medium
* @precision high
* @id java/weak-cryptographic-algorithm
* @tags security
* external/cwe/cwe-327

View File

@@ -17,7 +17,7 @@ import PathGraph
*/
private string getACredentialRegex() {
result = "(?i).*challenge|pass(wd|word|code|phrase)(?!.*question).*" or
result = "(?i)(.*username|url).*"
result = "(?i)(.*username|.*secret|url).*"
}
/** Variable keeps sensitive information judging by its name * */
@@ -31,8 +31,12 @@ class CredentialExpr extends Expr {
class LoggerType extends RefType {
LoggerType() {
this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J
this.hasQualifiedName("org.apache.logging.log4j", "Logger") or //Log4J 2
this.hasQualifiedName("org.slf4j", "Logger") or //SLF4j and Gradle Logging
this.hasQualifiedName("org.jboss.logging", "BasicLogger") //JBoss Logging
this.hasQualifiedName("org.jboss.logging", "BasicLogger") or //JBoss Logging
this.hasQualifiedName("org.jboss.logging", "Logger") or //JBoss Logging (`org.jboss.logging.Logger` in some implementations like JBoss Application Server 4.0.4 did not implement `BasicLogger`)
this.hasQualifiedName("org.apache.commons.logging", "Log") or //Apache Commons Logging
this.hasQualifiedName("org.scijava.log", "Logger") //SciJava Logging
}
}
@@ -42,7 +46,8 @@ predicate isSensitiveLoggingSink(DataFlow::Node sink) {
(
ma.getMethod().hasName("debug") or
ma.getMethod().hasName("trace") or
ma.getMethod().hasName("debugf")
ma.getMethod().hasName("debugf") or
ma.getMethod().hasName("debugv")
) and //Check low priority log levels which are more likely to be real issues to reduce false positives
sink.asExpr() = ma.getAnArgument()
)

View File

@@ -0,0 +1,49 @@
public class InsecureBasicAuth {
/**
* Test basic authentication with Apache HTTP request.
*/
public void testApacheHttpRequest(String username, String password) {
{
// BAD: basic authentication over HTTP
String url = "http://www.example.com/rest/getuser.do?uid=abcdx";
}
{
// GOOD: basic authentication over HTTPS
String url = "https://www.example.com/rest/getuser.do?uid=abcdx";
}
HttpPost post = new HttpPost(url);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
String authString = username + ":" + password;
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
String authStringEnc = new String(authEncBytes);
post.addHeader("Authorization", "Basic " + authStringEnc);
}
/**
* Test basic authentication with Java HTTP URL connection.
*/
public void testHttpUrlConnection(String username, String password) {
{
// BAD: basic authentication over HTTP
String urlStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
}
{
// GOOD: basic authentication over HTTPS
String urlStr = "https://www.example.com/rest/getuser.do?uid=abcdx";
}
String authString = username + ":" + password;
String encoding = Base64.getEncoder().encodeToString(authString.getBytes("UTF-8"));
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Authorization", "Basic " + encoding);
}
}

View File

@@ -0,0 +1,30 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>Basic authentication only obfuscates username/password in Base64 encoding, which can be easily recognized and reversed, thus it must not be transmitted over the cleartext HTTP channel. Transmission of sensitive information not in HTTPS is vulnerable to packet sniffing.</p>
</overview>
<recommendation>
<p>Either use a more secure authentication mechanism like digest authentication or federated authentication, or use the HTTPS communication protocol.</p>
</recommendation>
<example>
<p>The following example shows two ways of using basic authentication. In the 'BAD' case, the credentials are transmitted over HTTP. In the 'GOOD' case, the credentials are transmitted over HTTPS.</p>
<sample src="InsecureBasicAuth.java" />
</example>
<references>
<li>
<a href="https://cwe.mitre.org/data/definitions/522">CWE-522</a>
</li>
<li>
SonarSource rule:
<a href="https://rules.sonarsource.com/java/tag/owasp/RSPEC-2647">Basic authentication should not be used</a>
</li>
<li>
Acunetix:
<a href="https://www.acunetix.com/vulnerabilities/web/basic-authentication-over-http/">WEB VULNERABILITIES INDEX - Basic authentication over HTTP</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,263 @@
/**
* @name Insecure basic authentication
* @description Basic authentication only obfuscates username/password in Base64 encoding, which can be easily recognized and reversed. Transmission of sensitive information not over HTTPS is vulnerable to packet sniffing.
* @kind path-problem
* @id java/insecure-basic-auth
* @tags security
* external/cwe-522
* external/cwe-319
*/
import java
import semmle.code.java.frameworks.Networking
import semmle.code.java.dataflow.TaintTracking
import DataFlow::PathGraph
/**
* Gets a regular expression for matching private hosts, which only matches the host portion therefore checking for port is not necessary.
*/
private string getPrivateHostRegex() {
result =
"(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?"
}
/**
* The Java class `org.apache.http.client.methods.HttpRequestBase`. Popular subclasses include `HttpGet`, `HttpPost`, and `HttpPut`.
* And the Java class `org.apache.http.message.BasicHttpRequest`.
*/
class ApacheHttpRequest extends RefType {
ApacheHttpRequest() {
this
.getASourceSupertype*()
.hasQualifiedName("org.apache.http.client.methods", "HttpRequestBase") or
this.getASourceSupertype*().hasQualifiedName("org.apache.http.message", "BasicHttpRequest")
}
}
/**
* Class of Java URL constructor.
*/
class URLConstructor extends ClassInstanceExpr {
URLConstructor() { this.getConstructor().getDeclaringType() instanceof TypeUrl }
predicate hasHttpStringArg() {
this.getConstructor().getParameter(0).getType() instanceof TypeString and
(
// URLs constructed with any of the three string constructors below:
// `URL(String protocol, String host, int port, String file)`,
// `URL(String protocol, String host, int port, String file, URLStreamHandler handler)`,
// `URL(String protocol, String host, String file)`
this.getConstructor().getNumberOfParameters() > 1 and
concatHttpString(getArgument(0), this.getArgument(1)) // First argument contains the protocol part and the second argument contains the host part.
or
// URLs constructed with the string constructor `URL(String spec)`
this.getConstructor().getNumberOfParameters() = 1 and
this.getArgument(0) instanceof HttpString // First argument contains the whole spec.
)
}
}
/**
* Class of Java URI constructor.
*/
class URIConstructor extends ClassInstanceExpr {
URIConstructor() { this.getConstructor().getDeclaringType().hasQualifiedName("java.net", "URI") }
predicate hasHttpStringArg() {
(
this.getNumArgument() = 1 and
this.getArgument(0) instanceof HttpString // `URI(String str)`
or
this.getNumArgument() = 4 and
concatHttpString(this.getArgument(0), this.getArgument(1)) // `URI(String scheme, String host, String path, String fragment)`
or
this.getNumArgument() = 5 and
concatHttpString(this.getArgument(0), this.getArgument(1)) // `URI(String scheme, String authority, String path, String query, String fragment)` without user-info in authority
or
this.getNumArgument() = 7 and
concatHttpString(this.getArgument(0), this.getArgument(2)) // `URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)`
)
}
}
/**
* String of HTTP URLs not in private domains.
*/
class HttpStringLiteral extends StringLiteral {
HttpStringLiteral() {
// Match URLs with the HTTP protocol and without private IP addresses to reduce false positives.
exists(string s | this.getRepresentedString() = s |
s.regexpMatch("(?i)http://[\\[a-zA-Z0-9].*") and
not s.substring(7, s.length()).regexpMatch(getPrivateHostRegex())
)
}
}
/**
* Checks both parts of protocol and host.
*/
predicate concatHttpString(Expr protocol, Expr host) {
(
protocol.(CompileTimeConstantExpr).getStringValue().regexpMatch("(?i)http(://)?") or
protocol
.(VarAccess)
.getVariable()
.getAnAssignedValue()
.(CompileTimeConstantExpr)
.getStringValue()
.regexpMatch("(?i)http(://)?")
) and
not exists(string hostString |
hostString = host.(CompileTimeConstantExpr).getStringValue() or
hostString =
host.(VarAccess).getVariable().getAnAssignedValue().(CompileTimeConstantExpr).getStringValue()
|
hostString.length() = 0 or // Empty host is loopback address
hostString.regexpMatch(getPrivateHostRegex())
)
}
/** Gets the leftmost operand in a concatenated string */
Expr getLeftmostConcatOperand(Expr expr) {
if expr instanceof AddExpr
then result = getLeftmostConcatOperand(expr.(AddExpr).getLeftOperand())
else result = expr
}
/**
* String concatenated with `HttpStringLiteral`.
*/
class HttpString extends Expr {
HttpString() {
this instanceof HttpStringLiteral
or
concatHttpString(this.(AddExpr).getLeftOperand(),
getLeftmostConcatOperand(this.(AddExpr).getRightOperand()))
}
}
/**
* String pattern of basic authentication.
*/
class BasicAuthString extends StringLiteral {
BasicAuthString() { exists(string s | this.getRepresentedString() = s | s.matches("Basic %")) }
}
/**
* String concatenated with `BasicAuthString`.
*/
predicate builtFromBasicAuthStringConcat(Expr expr) {
expr instanceof BasicAuthString
or
builtFromBasicAuthStringConcat(expr.(AddExpr).getLeftOperand())
or
exists(Expr other | builtFromBasicAuthStringConcat(other) |
exists(Variable var | var.getAnAssignedValue() = other and var.getAnAccess() = expr)
)
}
/** The `openConnection` method of Java URL. Not to include `openStream` since it won't be used in this query. */
class HttpURLOpenMethod extends Method {
HttpURLOpenMethod() {
this.getDeclaringType() instanceof TypeUrl and
this.getName() = "openConnection"
}
}
/** Constructor of `ApacheHttpRequest` */
predicate apacheHttpRequest(DataFlow::Node node1, DataFlow::Node node2) {
exists(ConstructorCall cc |
cc.getConstructedType() instanceof ApacheHttpRequest and
node2.asExpr() = cc and
cc.getAnArgument() = node1.asExpr()
)
}
/** `URI` methods */
predicate createURI(DataFlow::Node node1, DataFlow::Node node2) {
exists(
URIConstructor cc // new URI
|
node2.asExpr() = cc and
cc.getArgument(0) = node1.asExpr()
)
or
exists(
StaticMethodAccess ma // URI.create
|
ma.getMethod().getDeclaringType().hasQualifiedName("java.net", "URI") and
ma.getMethod().hasName("create") and
node1.asExpr() = ma.getArgument(0) and
node2.asExpr() = ma
)
}
/** Constructors of `URL` */
predicate createURL(DataFlow::Node node1, DataFlow::Node node2) {
exists(URLConstructor cc |
node2.asExpr() = cc and
cc.getArgument(0) = node1.asExpr()
)
}
/** Method call of `HttpURLOpenMethod` */
predicate urlOpen(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma |
ma.getMethod() instanceof HttpURLOpenMethod and
node1.asExpr() = ma.getQualifier() and
ma = node2.asExpr()
)
}
/** Constructor of `BasicRequestLine` */
predicate basicRequestLine(DataFlow::Node node1, DataFlow::Node node2) {
exists(ConstructorCall mcc |
mcc.getConstructedType().hasQualifiedName("org.apache.http.message", "BasicRequestLine") and
mcc.getArgument(1) = node1.asExpr() and // `BasicRequestLine(String method, String uri, ProtocolVersion version)
node2.asExpr() = mcc
)
}
class BasicAuthFlowConfig extends TaintTracking::Configuration {
BasicAuthFlowConfig() { this = "InsecureBasicAuth::BasicAuthFlowConfig" }
override predicate isSource(DataFlow::Node src) {
src.asExpr() instanceof HttpString
or
exists(URLConstructor uc |
uc.hasHttpStringArg() and
src.asExpr() = uc.getArgument(0)
)
or
exists(URIConstructor uc |
uc.hasHttpStringArg() and
src.asExpr() = uc.getArgument(0)
)
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and
(
ma.getMethod().hasName("addHeader") or
ma.getMethod().hasName("setHeader") or
ma.getMethod().hasName("setRequestProperty")
) and
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "Authorization" and
builtFromBasicAuthStringConcat(ma.getArgument(1))
)
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
apacheHttpRequest(node1, node2) or
createURI(node1, node2) or
basicRequestLine(node1, node2) or
createURL(node1, node2) or
urlOpen(node1, node2)
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, BasicAuthFlowConfig config
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Insecure basic authentication from $@.", source.getNode(),
"HTTP url"

View File

@@ -1344,10 +1344,7 @@ class VarAccess extends Expr, @varaccess {
*/
predicate isLValue() {
exists(Assignment a | a.getDest() = this) or
exists(PreIncExpr e | e.getExpr() = this) or
exists(PreDecExpr e | e.getExpr() = this) or
exists(PostIncExpr e | e.getExpr() = this) or
exists(PostDecExpr e | e.getExpr() = this)
exists(UnaryAssignExpr e | e.getExpr() = this)
}
/**

View File

@@ -194,7 +194,16 @@ class TypeVariable extends BoundedType, @typevariable {
* and the second wildcard has a lower bound of `Float`.
*/
class Wildcard extends BoundedType, @wildcard {
/** Holds if this wildcard has an upper bound. */
/**
* Holds if this wildcard is either unconstrained (i.e. `?`) or
* has a type bound.
*/
override predicate hasTypeBound() { BoundedType.super.hasTypeBound() }
/**
* Holds if this wildcard is either unconstrained (i.e. `?`) or
* has an upper bound.
*/
predicate hasUpperBound() { wildcards(this, _, 1) }
/** Holds if this wildcard has a lower bound. */

View File

@@ -0,0 +1,146 @@
/**
* Definitions for reasoning about untrusted data used in APIs defined outside the
* database.
*/
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
/**
* A `Method` that is considered a "safe" external API from a security perspective.
*/
abstract class SafeExternalAPIMethod extends Method { }
/** The default set of "safe" external APIs. */
private class DefaultSafeExternalAPIMethod extends SafeExternalAPIMethod {
DefaultSafeExternalAPIMethod() {
this instanceof EqualsMethod
or
getName().regexpMatch("size|length|compareTo|getClass|lastIndexOf")
or
this.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "Validate")
or
getQualifiedName() = "Objects.equals"
or
getDeclaringType() instanceof TypeString and getName() = "equals"
or
getDeclaringType().hasQualifiedName("com.google.common.base", "Preconditions")
or
getDeclaringType().getPackage().getName().matches("org.junit%")
or
getDeclaringType().hasQualifiedName("com.google.common.base", "Strings") and
getName() = "isNullOrEmpty"
or
getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "StringUtils") and
getName() = "isNotEmpty"
or
getDeclaringType().hasQualifiedName("java.lang", "Character") and
getName() = "isDigit"
or
getDeclaringType().hasQualifiedName("java.lang", "String") and
getName().regexpMatch("equalsIgnoreCase|regionMatches")
or
getDeclaringType().hasQualifiedName("java.lang", "Boolean") and
getName() = "parseBoolean"
or
getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils") and
getName() = "closeQuietly"
or
getDeclaringType().hasQualifiedName("org.springframework.util", "StringUtils") and
getName().regexpMatch("hasText|isEmpty")
}
}
/** A node representing data being passed to an external API. */
class ExternalAPIDataNode extends DataFlow::Node {
Call call;
int i;
ExternalAPIDataNode() {
(
// Argument to call to a method
this.asExpr() = call.getArgument(i)
or
// Qualifier to call to a method which returns non trivial value
this.asExpr() = call.getQualifier() and
i = -1 and
not call.getCallee().getReturnType() instanceof VoidType and
not call.getCallee().getReturnType() instanceof BooleanType
) and
// Defined outside the source archive
not call.getCallee().fromSource() and
// Not a call to an method which is overridden in source
not exists(Method m |
m.getASourceOverriddenMethod() = call.getCallee().getSourceDeclaration() and
m.fromSource()
) and
// Not already modeled as a taint step
not exists(DataFlow::Node next | TaintTracking::localTaintStep(this, next)) and
// Not a call to a known safe external API
not call.getCallee() instanceof SafeExternalAPIMethod
}
/** Gets the called API `Method`. */
Method getMethod() { result = call.getCallee() }
/** Gets the index which is passed untrusted data (where -1 indicates the qualifier). */
int getIndex() { result = i }
/** Gets the description of the method being called. */
string getMethodDescription() {
result = getMethod().getDeclaringType().getPackage() + "." + getMethod().getQualifiedName()
}
}
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */
class UntrustedDataToExternalAPIConfig extends TaintTracking::Configuration {
UntrustedDataToExternalAPIConfig() { this = "UntrustedDataToExternalAPIConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalAPIDataNode }
}
/** A node representing untrusted data being passed to an external API. */
class UntrustedExternalAPIDataNode extends ExternalAPIDataNode {
UntrustedExternalAPIDataNode() { any(UntrustedDataToExternalAPIConfig c).hasFlow(_, this) }
/** Gets a source of untrusted data which is passed to this external API data node. */
DataFlow::Node getAnUntrustedSource() {
any(UntrustedDataToExternalAPIConfig c).hasFlow(result, this)
}
}
private newtype TExternalAPI =
TExternalAPIParameter(Method m, int index) {
exists(UntrustedExternalAPIDataNode n |
m = n.getMethod() and
index = n.getIndex()
)
}
/** An external API which is used with untrusted data. */
class ExternalAPIUsedWithUntrustedData extends TExternalAPI {
/** Gets a possibly untrusted use of this external API. */
UntrustedExternalAPIDataNode getUntrustedDataNode() {
this = TExternalAPIParameter(result.getMethod(), result.getIndex())
}
/** Gets the number of untrusted sources used with this external API. */
int getNumberOfUntrustedSources() {
result = count(getUntrustedDataNode().getAnUntrustedSource())
}
/** Gets a textual representation of this element. */
string toString() {
exists(Method m, int index, string indexString |
if index = -1 then indexString = "qualifier" else indexString = "param " + index
|
this = TExternalAPIParameter(m, index) and
result =
m.getDeclaringType().(RefType).getQualifiedName() + "." + m.getSignature() + " [" +
indexString + "]"
)
}
}

View File

@@ -0,0 +1,413 @@
/** Provides classes to reason about LDAP injection attacks. */
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.frameworks.Jndi
import semmle.code.java.frameworks.UnboundId
import semmle.code.java.frameworks.SpringLdap
import semmle.code.java.frameworks.ApacheLdap
/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
abstract class LdapInjectionSink extends DataFlow::Node { }
/** A sanitizer that prevents LDAP injection attacks. */
abstract class LdapInjectionSanitizer extends DataFlow::Node { }
/**
* A unit class for adding additional taint steps.
*
* Extend this class to add additional taint steps that should apply to the `LdapInjectionFlowConfig`.
*/
class LdapInjectionAdditionalTaintStep extends TaintTracking::Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for the `LdapInjectionFlowConfig` configuration.
*/
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
}
/** 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)
)
}
}
/** 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() {
this.getType() instanceof PrimitiveType or
this.getType() instanceof BoxedType
}
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `LdapName`,
* i.e. `new LdapName(tainted)`.
*/
private predicate ldapNameStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeLdapName |
n1.asExpr() = cc.getAnArgument() and
n2.asExpr() = cc
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `List<Rdn>` and `LdapName`,
* i.e. `new LdapName().addAll(tainted)`.
*/
private predicate ldapNameAddAllStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma |
n1.asExpr() = ma.getAnArgument() and
(n2.asExpr() = ma or n2.asExpr() = ma.getQualifier())
|
ma.getMethod() instanceof MethodLdapNameAddAll
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `LdapName` and `LdapName` or
* `String`, i.e. `taintedLdapName.clone()`, `taintedLdapName.getAll()`,
* `taintedLdapName.getRdns()` or `taintedLdapName.toString()`.
*/
private predicate ldapNameGetCloneStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma and
ma.getMethod() = m
|
m instanceof MethodLdapNameClone or
m instanceof MethodLdapNameGetAll or
m instanceof MethodLdapNameGetRdns or
m instanceof MethodLdapNameToString
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and UnboundID `Filter`,
* i.e. `Filter.create*(tainted)`.
*/
private predicate filterStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getAnArgument() and
n2.asExpr() = ma and
ma.getMethod() = m
|
m instanceof MethodUnboundIdFilterCreate or
m instanceof MethodUnboundIdFilterCreateANDFilter or
m instanceof MethodUnboundIdFilterCreateNOTFilter or
m instanceof MethodUnboundIdFilterCreateORFilter or
m instanceof MethodUnboundIdFilterSimplifyFilter
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between UnboundID `Filter` and `String`,
* i.e. `taintedFilter.toString()` or `taintedFilter.toString(buffer)`.
*/
private predicate filterToStringStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
(n2.asExpr() = ma or n2.asExpr() = ma.getAnArgument())
|
ma.getMethod() = m and
m.getDeclaringType() instanceof TypeUnboundIdLdapFilter and
(m.hasName("toString") or m.hasName("toNormalizedString"))
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and UnboundID
* `SearchRequest`, i.e. `new SearchRequest(tainted)`.
*/
private predicate unboundIdSearchRequestStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(ConstructorCall cc, int index, Parameter param |
cc.getConstructedType() instanceof TypeUnboundIdSearchRequest
|
n1.asExpr() = cc.getArgument(index) and
n2.asExpr() = cc and
cc.getConstructor().getParameter(index) = param and
not param.isVarargs()
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between UnboundID `SearchRequest`
* and UnboundID `SearchRequest`, i.e. `taintedSearchRequest.duplicate()`.
*/
private predicate unboundIdSearchRequestDuplicateStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m | n1.asExpr() = ma.getQualifier() and n2.asExpr() = ma |
ma.getMethod() = m and
m.getDeclaringType().getAnAncestor() instanceof TypeUnboundIdReadOnlySearchRequest and
m.hasName("duplicate")
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between DN or filter and UnboundID
* `SearchRequest`, i.e. `searchRequest.setBaseDN(tainted)` or `searchRequest.setFilter(tainted)`.
*/
private predicate unboundIdSearchRequestSetStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getAnArgument() and
n2.asExpr() = ma.getQualifier() and
ma.getMethod() = m
|
m instanceof MethodUnboundIdSearchRequestSetBaseDN or
m instanceof MethodUnboundIdSearchRequestSetFilter
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Spring `LdapQuery`,
* i.e. `LdapQueryBuilder.query().filter(tainted)` or `LdapQueryBuilder.query().base(tainted)`.
*/
private predicate ldapQueryStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m, int index |
n1.asExpr() = ma.getArgument(index) and
n2.asExpr() = ma and
ma.getMethod() = m and
index = 0
|
m instanceof MethodSpringLdapQueryBuilderFilter or
m instanceof MethodSpringLdapQueryBuilderBase
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Spring `LdapQueryBuilder` and
* `Name`, i.e. `taintedLdapQueryBuilder.base()`.
*/
private predicate ldapQueryBaseStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma and
ma.getMethod() = m
|
m instanceof MethodSpringLdapQueryBuilderBase and
m.getNumberOfParameters() = 0
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Spring `LdapQueryBuilder`,
* `ConditionCriteria` or `ContainerCriteria`, i.e. when the query is built, for example
* `query().base(tainted).where("objectclass").is("person")`.
*/
private predicate ldapQueryBuilderStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma and
ma.getMethod() = m
|
(
m.getDeclaringType() instanceof TypeSpringLdapQueryBuilder or
m.getDeclaringType() instanceof TypeSpringConditionCriteria or
m.getDeclaringType() instanceof TypeSpringContainerCriteria
) and
(
m.getReturnType() instanceof TypeSpringLdapQueryBuilder or
m.getReturnType() instanceof TypeSpringConditionCriteria or
m.getReturnType() instanceof TypeSpringContainerCriteria
)
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Spring
* `HardcodedFilter`, i.e. `new HardcodedFilter(tainted)`.
*/
private predicate hardcodedFilterStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeSpringHardcodedFilter |
n1.asExpr() = cc.getAnArgument() and
n2.asExpr() = cc
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Spring `Filter` and
* `String`, i.e. `taintedFilter.toString()`, `taintedFilter.encode()` or
* `taintedFilter.encode(buffer)`.
*/
private predicate springLdapFilterToStringStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getQualifier() and
(n2.asExpr() = ma or n2.asExpr() = ma.getAnArgument()) and
ma.getMethod() = m
|
m.getDeclaringType().getAnAncestor() instanceof TypeSpringLdapFilter and
(m.hasName("encode") or m.hasName("toString"))
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Spring
* `LdapNameBuilder`, i.e. `LdapNameBuilder.newInstance(tainted)` or
* `LdapNameBuilder.newInstance().add(tainted)`.
*/
private predicate ldapNameBuilderStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getAnArgument() and
(n2.asExpr() = ma or n2.asExpr() = ma.getQualifier()) and
ma.getMethod() = m and
m.getNumberOfParameters() = 1
|
m instanceof MethodSpringLdapNameBuilderNewInstance or
m instanceof MethodSpringLdapNameBuilderAdd
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between tainted Spring `LdapNameBuilder`
* and `LdapName`, `LdapNameBuilder.build()`.
*/
private predicate ldapNameBuilderBuildStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma | n1.asExpr() = ma.getQualifier() and n2.asExpr() = ma |
ma.getMethod() instanceof MethodSpringLdapNameBuilderBuild
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `LdapName` via
* Spring `LdapUtils.newLdapName`, i.e. `LdapUtils.newLdapName(tainted)`.
*/
private predicate ldapUtilsStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma | n1.asExpr() = ma.getAnArgument() and n2.asExpr() = ma |
ma.getMethod() instanceof MethodSpringLdapUtilsNewLdapName
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Apache LDAP API
* `SearchRequest`, i.e. `searchRequest.setFilter(tainted)` or `searchRequest.setBase(tainted)`.
*/
private predicate apacheSearchRequestStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m |
n1.asExpr() = ma.getAnArgument() and
n2.asExpr() = ma.getQualifier()
|
ma.getMethod() = m and
m.getDeclaringType().getAnAncestor() instanceof TypeApacheSearchRequest and
(m.hasName("setFilter") or m.hasName("setBase"))
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Apache LDAP API `SearchRequest`
* and filter or DN i.e. `tainterSearchRequest.getFilter()` or `taintedSearchRequest.getBase()`.
*/
private predicate apacheSearchRequestGetStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m | n1.asExpr() = ma.getQualifier() and n2.asExpr() = ma |
ma.getMethod() = m and
m.getDeclaringType().getAnAncestor() instanceof TypeApacheSearchRequest and
(m.hasName("getFilter") or m.hasName("getBase"))
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and Apache LDAP API
* `Dn`, i.e. `new Dn(tainted)`.
*/
private predicate apacheLdapDnStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeApacheDn |
n1.asExpr() = cc.getAnArgument() and
n2.asExpr() = cc
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between Apache LDAP API `Dn`
* and `String` i.e. `taintedDn.getName()`, `taintedDn.getNormName()` or `taintedDn.toString()`.
*/
private predicate apacheLdapDnGetStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(MethodAccess ma, Method m | n1.asExpr() = ma.getQualifier() and n2.asExpr() = ma |
ma.getMethod() = m and
m.getDeclaringType().getAnAncestor() instanceof TypeApacheDn and
(m.hasName("getName") or m.hasName("getNormName") or m.hasName("toString"))
)
}
/** A set of additional taint steps to consider when taint tracking LDAP related data flows. */
private class DefaultLdapInjectionAdditionalTaintStep extends LdapInjectionAdditionalTaintStep {
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
ldapNameStep(node1, node2) or
ldapNameAddAllStep(node1, node2) or
ldapNameGetCloneStep(node1, node2) or
filterStep(node1, node2) or
filterToStringStep(node1, node2) or
unboundIdSearchRequestStep(node1, node2) or
unboundIdSearchRequestDuplicateStep(node1, node2) or
unboundIdSearchRequestSetStep(node1, node2) or
ldapQueryStep(node1, node2) or
ldapQueryBaseStep(node1, node2) or
ldapQueryBuilderStep(node1, node2) or
hardcodedFilterStep(node1, node2) or
springLdapFilterToStringStep(node1, node2) or
ldapNameBuilderStep(node1, node2) or
ldapNameBuilderBuildStep(node1, node2) or
ldapUtilsStep(node1, node2) or
apacheSearchRequestStep(node1, node2) or
apacheSearchRequestGetStep(node1, node2) or
apacheLdapDnStep(node1, node2) or
apacheLdapDnGetStep(node1, node2)
}
}

View File

@@ -0,0 +1,141 @@
/**
* Models the different ways to create paths. Either by using `java.io.File`-related APIs or `java.nio.file.Path`-related APIs.
*/
import java
/** Models the creation of a path. */
abstract class PathCreation extends Expr {
/**
* Gets an input that is used in the creation of this path.
* This excludes inputs of type `File` and `Path`.
*/
abstract Expr getAnInput();
}
/** Models the `java.nio.file.Paths.get` method. */
private class PathsGet extends PathCreation, MethodAccess {
PathsGet() {
exists(Method m | m = this.getMethod() |
m.getDeclaringType() instanceof TypePaths and
m.getName() = "get"
)
}
override Expr getAnInput() { result = this.getAnArgument() }
}
/** Models the `java.nio.file.FileSystem.getPath` method. */
private class FileSystemGetPath extends PathCreation, MethodAccess {
FileSystemGetPath() {
exists(Method m | m = this.getMethod() |
m.getDeclaringType() instanceof TypeFileSystem and
m.getName() = "getPath"
)
}
override Expr getAnInput() { result = this.getAnArgument() }
}
/** Models the `new java.io.File(...)` constructor. */
private class FileCreation extends PathCreation, ClassInstanceExpr {
FileCreation() { this.getConstructedType() instanceof TypeFile }
override Expr getAnInput() {
result = this.getAnArgument() and
// Relevant arguments include those that are not a `File`.
not result.getType() instanceof TypeFile
}
}
/** Models the `java.nio.file.Path.resolveSibling` method. */
private class PathResolveSiblingCreation extends PathCreation, MethodAccess {
PathResolveSiblingCreation() {
exists(Method m | m = this.getMethod() |
m.getDeclaringType() instanceof TypePath and
m.getName() = "resolveSibling"
)
}
override Expr getAnInput() {
result = this.getAnArgument() and
// Relevant arguments are those of type `String`.
result.getType() instanceof TypeString
}
}
/** Models the `java.nio.file.Path.resolve` method. */
private class PathResolveCreation extends PathCreation, MethodAccess {
PathResolveCreation() {
exists(Method m | m = this.getMethod() |
m.getDeclaringType() instanceof TypePath and
m.getName() = "resolve"
)
}
override Expr getAnInput() {
result = this.getAnArgument() and
// Relevant arguments are those of type `String`.
result.getType() instanceof TypeString
}
}
/** Models the `java.nio.file.Path.of` method. */
private class PathOfCreation extends PathCreation, MethodAccess {
PathOfCreation() {
exists(Method m | m = this.getMethod() |
m.getDeclaringType() instanceof TypePath and
m.getName() = "of"
)
}
override Expr getAnInput() { result = this.getAnArgument() }
}
/** Models the `new java.io.FileWriter(...)` constructor. */
private class FileWriterCreation extends PathCreation, ClassInstanceExpr {
FileWriterCreation() { this.getConstructedType().hasQualifiedName("java.io", "FileWriter") }
override Expr getAnInput() {
result = this.getAnArgument() and
// Relevant arguments are those of type `String`.
result.getType() instanceof TypeString
}
}
/** Models the `new java.io.FileReader(...)` constructor. */
private class FileReaderCreation extends PathCreation, ClassInstanceExpr {
FileReaderCreation() { this.getConstructedType().hasQualifiedName("java.io", "FileReader") }
override Expr getAnInput() {
result = this.getAnArgument() and
// Relevant arguments are those of type `String`.
result.getType() instanceof TypeString
}
}
/** Models the `new java.io.FileInputStream(...)` constructor. */
private class FileInputStreamCreation extends PathCreation, ClassInstanceExpr {
FileInputStreamCreation() {
this.getConstructedType().hasQualifiedName("java.io", "FileInputStream")
}
override Expr getAnInput() {
result = this.getAnArgument() and
// Relevant arguments are those of type `String`.
result.getType() instanceof TypeString
}
}
/** Models the `new java.io.FileOutputStream(...)` constructor. */
private class FileOutputStreamCreation extends PathCreation, ClassInstanceExpr {
FileOutputStreamCreation() {
this.getConstructedType().hasQualifiedName("java.io", "FileOutputStream")
}
override Expr getAnInput() {
result = this.getAnArgument() and
// Relevant arguments are those of type `String`.
result.getType() instanceof TypeString
}
}

View File

@@ -0,0 +1,49 @@
/** Provides classes to reason about header splitting attacks. */
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.Servlets
import semmle.code.java.frameworks.JaxWS
/** A sink that is vulnerable to an HTTP header splitting attack. */
abstract class HeaderSplittingSink extends DataFlow::Node { }
/** A source that introduces data considered safe to use by a header splitting source. */
abstract class SafeHeaderSplittingSource extends DataFlow::Node {
SafeHeaderSplittingSource() { this instanceof RemoteFlowSource }
}
/** A sink that identifies a Java Servlet or JaxWs method that is vulnerable to an HTTP header splitting attack. */
private class ServletHeaderSplittingSink extends HeaderSplittingSink {
ServletHeaderSplittingSink() {
exists(ResponseAddCookieMethod m, MethodAccess ma |
ma.getMethod() = m and
this.asExpr() = ma.getArgument(0)
)
or
exists(ResponseAddHeaderMethod m, MethodAccess ma |
ma.getMethod() = m and
this.asExpr() = ma.getAnArgument()
)
or
exists(ResponseSetHeaderMethod m, MethodAccess ma |
ma.getMethod() = m and
this.asExpr() = ma.getAnArgument()
)
or
exists(JaxRsResponseBuilder builder, Method m |
m = builder.getAMethod() and m.getName() = "header"
|
this.asExpr() = m.getAReference().getArgument(1)
)
}
}
/** A default source that introduces data considered safe to use by a header splitting source. */
private class DefaultSafeHeaderSplittingSource extends SafeHeaderSplittingSource {
DefaultSafeHeaderSplittingSource() {
this.asExpr().(MethodAccess).getMethod() instanceof HttpServletRequestGetHeaderMethod or
this.asExpr().(MethodAccess).getMethod() instanceof CookieGetNameMethod
}
}

View File

@@ -97,6 +97,7 @@ class WritingMethod extends Method {
(
this.getName().matches("print%") or
this.getName() = "append" or
this.getName() = "format" or
this.getName() = "write"
)
}

View File

@@ -0,0 +1,43 @@
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:54:3:54:6 | post |
| 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: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 |
| InsecureBasicAuth.java:126:19:126:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:130:28:130:67 | (...)... : URLConnection |
| InsecureBasicAuth.java:130:28:130:67 | (...)... : URLConnection | InsecureBasicAuth.java:133:3:133:6 | conn |
| InsecureBasicAuth.java:145:21:145:28 | protocol : String | InsecureBasicAuth.java:146:28:146:67 | (...)... : URLConnection |
| InsecureBasicAuth.java:146:28:146:67 | (...)... : URLConnection | InsecureBasicAuth.java:149:3:149:6 | conn |
nodes
| InsecureBasicAuth.java:20:39:20:52 | ... + ... : String | semmle.label | ... + ... : String |
| InsecureBasicAuth.java:28:3:28:6 | post | semmle.label | post |
| 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: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: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 |
| InsecureBasicAuth.java:93:19:93: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:102:3:102:6 | post | semmle.label | post |
| InsecureBasicAuth.java:109:19:109: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:119:3:119:6 | post | semmle.label | post |
| InsecureBasicAuth.java:126:19:126: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:130:28:130:67 | (...)... : URLConnection | semmle.label | (...)... : URLConnection |
| InsecureBasicAuth.java:133:3:133:6 | conn | semmle.label | conn |
| InsecureBasicAuth.java:145:21:145:28 | protocol : String | semmle.label | protocol : String |
| InsecureBasicAuth.java:146:28:146:67 | (...)... : URLConnection | semmle.label | (...)... : URLConnection |
| InsecureBasicAuth.java:149:3:149:6 | conn | semmle.label | conn |
#select
| InsecureBasicAuth.java:28:3:28:6 | post | InsecureBasicAuth.java:20:39:20:52 | ... + ... : String | InsecureBasicAuth.java:28:3:28:6 | post | Insecure basic authentication from $@. | InsecureBasicAuth.java:20:39:20:52 | ... + ... | HTTP url |
| InsecureBasicAuth.java:38:3:38:5 | get | InsecureBasicAuth.java:35:19:35:64 | "http://www.example.com:8000/payment/retrieve" : String | InsecureBasicAuth.java:38:3:38:5 | get | Insecure basic authentication from $@. | InsecureBasicAuth.java:35:19:35:64 | "http://www.example.com:8000/payment/retrieve" | HTTP url |
| InsecureBasicAuth.java:54:3:54:6 | post | InsecureBasicAuth.java:45:19:45:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:54:3:54:6 | post | Insecure basic authentication from $@. | InsecureBasicAuth.java:45:19:45:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" | HTTP url |
| InsecureBasicAuth.java:71:3:71:6 | post | InsecureBasicAuth.java:61:19:61:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:71:3:71:6 | post | Insecure basic authentication from $@. | InsecureBasicAuth.java:61:19:61:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" | HTTP url |
| InsecureBasicAuth.java:86:3:86:6 | post | InsecureBasicAuth.java:78:47:78:52 | "http" : String | InsecureBasicAuth.java:86:3:86:6 | post | Insecure basic authentication from $@. | InsecureBasicAuth.java:78:47:78:52 | "http" | HTTP url |
| InsecureBasicAuth.java:102:3:102: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 | Insecure basic authentication from $@. | InsecureBasicAuth.java:93:19:93:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" | HTTP url |
| InsecureBasicAuth.java:119:3:119: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 | Insecure basic authentication from $@. | InsecureBasicAuth.java:109:19:109:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" | HTTP url |
| InsecureBasicAuth.java:133:3:133:6 | conn | InsecureBasicAuth.java:126:19:126:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:133:3:133:6 | conn | Insecure basic authentication from $@. | InsecureBasicAuth.java:126:19:126:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" | HTTP url |
| InsecureBasicAuth.java:149:3:149:6 | conn | InsecureBasicAuth.java:145:21:145:28 | protocol : String | InsecureBasicAuth.java:149:3:149:6 | conn | Insecure basic authentication from $@. | InsecureBasicAuth.java:145:21:145:28 | protocol | HTTP url |

View File

@@ -0,0 +1,164 @@
import org.apache.http.RequestLine;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.BasicRequestLine;
import java.net.URI;
import java.net.URL;
import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.util.Base64;
public class InsecureBasicAuth {
/**
* Test basic authentication with Apache HTTP POST request using string constructor.
*/
public void testApacheHttpRequest(String username, String password) {
String host = "www.example.com";
HttpRequestBase post = new HttpPost("http://"+host+"/rest/getuser.do?uid=abcdx");
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
String authString = username + ":" + password;
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
String authStringEnc = new String(authEncBytes);
post.addHeader("Authorization", "Basic " + authStringEnc);
}
/**
* Test basic authentication with Apache HTTP GET request.
*/
public void testApacheHttpRequest2(String url) throws java.io.IOException {
String urlStr = "http://www.example.com:8000/payment/retrieve";
HttpGet get = new HttpGet(urlStr);
get.setHeader("Accept", "application/json");
get.setHeader("Authorization", "Basic " + new String(Base64.getEncoder().encode("admin:test".getBytes())));
}
/**
* Test basic authentication with Apache HTTP POST request using URI create method.
*/
public void testApacheHttpRequest3(String username, String password) {
String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
HttpRequestBase post = new HttpPost(URI.create(uriStr));
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
String authString = username + ":" + password;
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
String authStringEnc = new String(authEncBytes);
post.addHeader("Authorization", "Basic " + authStringEnc);
}
/**
* Test basic authentication with Apache HTTP POST request using the URI constructor with one argument.
*/
public void testApacheHttpRequest4(String username, String password) {
String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
URI uri = new URI(uriStr);
HttpRequestBase post = new HttpPost(uri);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
String authString = username + ":" + password;
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
String authStringEnc = new String(authEncBytes);
post.addHeader("Authorization", "Basic " + authStringEnc);
}
/**
* Test basic authentication with Apache HTTP POST request using a URI constructor with multiple arguments.
*/
public void testApacheHttpRequest5(String username, String password) {
HttpRequestBase post = new HttpPost(new URI("http", "www.example.com", "/test", "abc=123", null));
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
String authString = username + ":" + password;
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
String authStringEnc = new String(authEncBytes);
post.addHeader("Authorization", "Basic " + authStringEnc);
}
/**
* Test basic authentication with Apache HTTP `BasicHttpRequest` using string constructor.
*/
public void testApacheHttpRequest6(String username, String password) {
String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
BasicHttpRequest post = new BasicHttpRequest("POST", uriStr);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
String authString = username + ":" + password;
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
String authStringEnc = new String(authEncBytes);
post.addHeader("Authorization", "Basic " + authStringEnc);
}
/**
* Test basic authentication with Apache HTTP `BasicHttpRequest` using `RequestLine`.
*/
public void testApacheHttpRequest7(String username, String password) {
String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
RequestLine requestLine = new BasicRequestLine("POST", uriStr, null);
BasicHttpRequest post = new BasicHttpRequest(requestLine);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
String authString = username + ":" + password;
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
String authStringEnc = new String(authEncBytes);
post.addHeader("Authorization", "Basic " + authStringEnc);
}
/**
* Test basic authentication with Java HTTP URL connection using the `URL(String spec)` constructor.
*/
public void testHttpUrlConnection(String username, String password) {
String urlStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
String authString = username + ":" + password;
String encoding = Base64.getEncoder().encodeToString(authString.getBytes("UTF-8"));
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Authorization", "Basic " + encoding);
}
/**
* Test basic authentication with Java HTTP URL connection using the `URL(String protocol, String host, String file)` constructor.
*/
public void testHttpUrlConnection2(String username, String password) {
String host = "www.example.com";
String path = "/rest/getuser.do?uid=abcdx";
String protocol = "http";
String authString = username + ":" + password;
String encoding = Base64.getEncoder().encodeToString(authString.getBytes("UTF-8"));
URL url = new URL(protocol, host, path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Authorization", "Basic " + encoding);
}
/**
* Test basic authentication with Java HTTP URL connection using a constructor with private URL.
*/
public void testHttpUrlConnection3(String username, String password) {
String host = "LOCALHOST";
String authString = username + ":" + password;
String encoding = Base64.getEncoder().encodeToString(authString.getBytes("UTF-8"));
HttpURLConnection conn = (HttpURLConnection) new URL("http://"+(((host+"/rest/getuser.do")+"?uid=abcdx"))).openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Authorization", "Basic " + encoding);
}
}

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql

View File

@@ -0,0 +1 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13

View File

@@ -0,0 +1,25 @@
| PathCreation.java:13:18:13:32 | new File(...) | PathCreation.java:13:27:13:31 | "dir" |
| PathCreation.java:14:19:14:40 | new File(...) | PathCreation.java:14:28:14:32 | "dir" |
| PathCreation.java:14:19:14:40 | new File(...) | PathCreation.java:14:35:14:39 | "sub" |
| PathCreation.java:18:18:18:49 | new File(...) | PathCreation.java:18:44:18:48 | "sub" |
| PathCreation.java:18:27:18:41 | new File(...) | PathCreation.java:18:36:18:40 | "dir" |
| PathCreation.java:22:18:22:41 | new File(...) | PathCreation.java:22:27:22:40 | new URI(...) |
| PathCreation.java:26:18:26:31 | of(...) | PathCreation.java:26:26:26:30 | "dir" |
| PathCreation.java:27:19:27:39 | of(...) | PathCreation.java:27:27:27:31 | "dir" |
| PathCreation.java:27:19:27:39 | of(...) | PathCreation.java:27:34:27:38 | "sub" |
| PathCreation.java:31:18:31:40 | of(...) | PathCreation.java:31:26:31:39 | new URI(...) |
| PathCreation.java:35:18:35:33 | get(...) | PathCreation.java:35:28:35:32 | "dir" |
| PathCreation.java:36:19:36:41 | get(...) | PathCreation.java:36:29:36:33 | "dir" |
| PathCreation.java:36:19:36:41 | get(...) | PathCreation.java:36:36:36:40 | "sub" |
| PathCreation.java:40:18:40:42 | get(...) | PathCreation.java:40:28:40:41 | new URI(...) |
| PathCreation.java:44:18:44:56 | getPath(...) | PathCreation.java:44:51:44:55 | "dir" |
| PathCreation.java:45:19:45:64 | getPath(...) | PathCreation.java:45:52:45:56 | "dir" |
| PathCreation.java:45:19:45:64 | getPath(...) | PathCreation.java:45:59:45:63 | "sub" |
| PathCreation.java:49:18:49:31 | of(...) | PathCreation.java:49:26:49:30 | "dir" |
| PathCreation.java:49:18:49:53 | resolveSibling(...) | PathCreation.java:49:48:49:52 | "sub" |
| PathCreation.java:53:18:53:31 | of(...) | PathCreation.java:53:26:53:30 | "dir" |
| PathCreation.java:53:18:53:46 | resolve(...) | PathCreation.java:53:41:53:45 | "sub" |
| PathCreation.java:57:25:57:45 | new FileWriter(...) | PathCreation.java:57:40:57:44 | "dir" |
| PathCreation.java:61:25:61:45 | new FileReader(...) | PathCreation.java:61:40:61:44 | "dir" |
| PathCreation.java:65:32:65:58 | new FileOutputStream(...) | PathCreation.java:65:53:65:57 | "dir" |
| PathCreation.java:69:31:69:56 | new FileInputStream(...) | PathCreation.java:69:51:69:55 | "dir" |

View File

@@ -0,0 +1,71 @@
import java.io.File;
import java.io.FileWriter;
import java.io.FileReader;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.FileSystems;
import java.net.URI;
class PathCreation {
public void testNewFileWithString() {
File f = new File("dir");
File f2 = new File("dir", "sub");
}
public void testNewFileWithFileString() {
File f = new File(new File("dir"), "sub");
}
public void testNewFileWithURI() {
File f = new File(new URI("dir"));
}
public void testPathOfWithString() {
Path p = Path.of("dir");
Path p2 = Path.of("dir", "sub");
}
public void testPathOfWithURI() {
Path p = Path.of(new URI("dir"));
}
public void testPathsGetWithString() {
Path p = Paths.get("dir");
Path p2 = Paths.get("dir", "sub");
}
public void testPathsGetWithURI() {
Path p = Paths.get(new URI("dir"));
}
public void testFileSystemGetPathWithString() {
Path p = FileSystems.getDefault().getPath("dir");
Path p2 = FileSystems.getDefault().getPath("dir", "sub");
}
public void testPathResolveSiblingWithString() {
Path p = Path.of("dir").resolveSibling("sub");
}
public void testPathResolveWithString() {
Path p = Path.of("dir").resolve("sub");
}
public void testNewFileWriterWithString() {
FileWriter fw = new FileWriter("dir");
}
public void testNewFileReaderWithString() {
FileReader fr = new FileReader("dir");
}
public void testNewFileOutputStreamWithString() {
FileOutputStream fos = new FileOutputStream("dir");
}
public void testNewFileInputStreamWithString() {
FileInputStream fis = new FileInputStream("dir");
}
}

View File

@@ -0,0 +1,5 @@
import java
import semmle.code.java.security.PathCreation
from PathCreation path
select path, path.getAnInput()

View File

@@ -0,0 +1,70 @@
/*
* $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/Header.java $
* $Revision: 569636 $
* $Date: 2007-08-25 00:34:47 -0700 (Sat, 25 Aug 2007) $
*
* ====================================================================
* 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http;
/**
* Represents an HTTP header field.
*
* <p>
* The HTTP header fields follow the same generic format as that given in
* Section 3.1 of RFC 822. Each header field consists of a name followed by a
* colon (":") and the field value. Field names are case-insensitive. The field
* value MAY be preceded by any amount of LWS, though a single SP is preferred.
*
* <pre>
* message-header = field-name ":" [ field-value ]
* field-name = token
* field-value = *( field-content | LWS )
* field-content = &lt;the OCTETs making up the field-value
* and consisting of either *TEXT or combinations
* of token, separators, and quoted-string&gt;
* </pre>
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
* @version $Revision: 569636 $
*
* @deprecated Please use {@link java.net.URL#openConnection} instead. Please
* visit <a href=
* "http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this
* webpage</a> for further details.
*/
@Deprecated
public interface Header {
String getName();
String getValue();
HeaderElement[] getElements() throws ParseException;
}

View File

@@ -0,0 +1,65 @@
/*
* $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/HeaderElement.java $
* $Revision: 569828 $
* $Date: 2007-08-26 08:49:38 -0700 (Sun, 26 Aug 2007) $
*
* ====================================================================
* 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http;
/**
* One element of an HTTP {@link Header header} value.
*
* @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
*
*
* <!-- empty lines above to avoid 'svn diff' context problems -->
* @version $Revision: 569828 $ $Date: 2007-08-26 08:49:38 -0700 (Sun, 26 Aug
* 2007) $
*
* @since 4.0
*
* @deprecated Please use {@link java.net.URL#openConnection} instead. Please
* visit <a href=
* "http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this
* webpage</a> for further details.
*/
@Deprecated
public interface HeaderElement {
String getName();
String getValue();
NameValuePair[] getParameters();
NameValuePair getParameterByName(String name);
int getParameterCount();
NameValuePair getParameter(int index);
}

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