Compare commits

..

603 Commits

Author SHA1 Message Date
Max Schaefer
c8b112da19 Automodel: Exclude features from Kotlin files. 2024-01-09 11:43:22 +00:00
Tony Torralba
1b9f59efa7 Merge pull request #14646 from github/java/update-mad-decls-after-triage-2023-10-31T15-52-01
Java: Update MaD Declarations after Triage
2023-12-20 15:37:19 +01:00
Tony Torralba
e744d974e8 Merge pull request #14580 from github/java/update-mad-decls-after-triage-2023-10-24T15-42-01
Java: Update MaD Declarations after Triage
2023-12-20 15:01:24 +01:00
Tony Torralba
2df8bcb9dc Update java/ql/lib/change-notes/2023-10-31-new-models.md
Co-authored-by: Jami <57204504+jcogs33@users.noreply.github.com>
2023-12-20 14:59:07 +01:00
yoff
19813c8ba6 Merge pull request #15166 from yoff/python/add-scope-entry-definition-nodes
Python: Add scope entry definition nodes
2023-12-20 13:14:11 +01:00
Rasmus Lerchedahl Petersen
7749b8e60e Python: add change-note 2023-12-20 12:53:37 +01:00
Mathias Vorreiter Pedersen
be3f9d3078 Merge pull request #15173 from jketema/unneeded 2023-12-20 12:43:42 +01:00
Rasmus Lerchedahl Petersen
07c88dc0be Python: remove unnecessary post-processing
also, it is slightly incorrect...
2023-12-20 12:09:15 +01:00
Rasmus Lerchedahl Petersen
169d7a3c98 Python: Add scope entry definition nodes
otherwise we confuse captured variables
in the single scope entry cfg node. Now
we have one for each defined variable.
2023-12-20 12:09:00 +01:00
Rasmus Lerchedahl Petersen
3b7e29bed6 Python: add test for crosstalk 2023-12-20 12:08:05 +01:00
Tamás Vajk
d3c685a41a Merge pull request #15156 from tamasvajk/standalone/temp-folder-structure
C#: Fix working directory structures in standalone
2023-12-20 11:57:42 +01:00
Tamas Vajk
b1413a1d98 Add readonly to tempFolderPath field 2023-12-20 11:16:52 +01:00
Mathias Vorreiter Pedersen
44124158c4 Merge pull request #15078 from alexet/unique-pointer-temporary
CPP: Add query for detecting invalid uses of temporary unique pointers.
2023-12-20 11:16:01 +01:00
Tamas Vajk
90fc54ca05 Apply review feedback: use Lazy<> instead of locking 2023-12-20 11:04:39 +01:00
Koen Vlaswinkel
32d1f057df Merge pull request #15159 from github/koesie10/csharp-model-editor-tests
C#: Classify test support files in model editor queries
2023-12-20 10:54:24 +01:00
Mathias Vorreiter Pedersen
57e0804cef Update cpp/ql/src/Security/CWE/CWE-416/UseOfUniquePointerAfterLifetimeEnds.ql
Co-authored-by: Felicity Chapman <felicitymay@github.com>
2023-12-20 10:52:42 +01:00
Tamas Vajk
dc36cdbede Only delete dotnet-install.sh if not in scratch directory 2023-12-20 10:51:23 +01:00
Jeroen Ketema
12abf07d1d C++: Remove unneeded extractor option 2023-12-20 09:58:32 +01:00
Michael Nebel
6831775a8d Merge pull request #15154 from michaelnebel/csharp/morestubs
C#: Replace more hand written stubs with generated ones.
2023-12-20 09:54:19 +01:00
Koen Vlaswinkel
d09fadf22e C#: Introduce TestRelatedFile class 2023-12-20 09:53:51 +01:00
Óscar San José
b55c299533 Merge pull request #15112 from fossilet/upstream_main
Fix sphinx.add_lexer.
2023-12-19 21:28:24 +01:00
Edward Minnix III
06544e989e Merge pull request #15126 from egregius313/egregius313/java/minor/add-replace-to-mapmutator
Java: Add the `Map#replace` and `Map#replaceAll` methods to `MapMutator` in `Maps.qll`
2023-12-19 12:10:34 -05:00
Koen Vlaswinkel
0f71df9c41 C#: Extend TestFile instead of separate class 2023-12-19 16:37:49 +01:00
Ed Minnix
a93d6dd956 Change note 2023-12-19 10:28:23 -05:00
Ed Minnix
ce130c6ed5 Add replace to MapMutator 2023-12-19 10:23:06 -05:00
Jeroen Ketema
4009b42891 Merge pull request #15146 from jketema/almost-empty-pch
C++: Update test after extractor changes
2023-12-19 16:20:35 +01:00
Tamas Vajk
278d9b1dfb Fix integration tests 2023-12-19 15:33:46 +01:00
Michael Nebel
681ac7e5f0 C#: Update tests (and expected output) to use the generated EntityFramework stubs. 2023-12-19 15:22:45 +01:00
Michael Nebel
80f3c6cc2b C#: Manual changes to the project dependecies to avoid conflicts when multiple projects are loaded from source. 2023-12-19 15:21:56 +01:00
Michael Nebel
272f3265ea C#: Delete the handwritten EntityFramework stubs. 2023-12-19 15:20:53 +01:00
Tamas Vajk
016d200355 Fix unit tests 2023-12-19 15:14:47 +01:00
Tony Torralba
c8a369d9ef Update java/ql/lib/ext/jakarta.persistence.model.yml 2023-12-19 14:58:07 +01:00
Mathias Vorreiter Pedersen
cfaa2d881a Merge pull request #15152 from MathiasVP/fix-unnecessary-evaluation-of-debug-strings
C++: Fix unnecessary evaluation of debug strings
2023-12-19 13:59:20 +01:00
Koen Vlaswinkel
d22acfb449 C#: Classify test support files in model editor queries 2023-12-19 13:49:53 +01:00
Tamas Vajk
ad394a0d84 C#: Download dotnet-install.sh to the scratch dir 2023-12-19 13:11:22 +01:00
Tamas Vajk
dd64b436c0 C#: Fix working directory structures in standalone 2023-12-19 12:54:00 +01:00
Mathias Vorreiter Pedersen
95cd31fce3 C++: Silence warnings. 2023-12-19 12:29:16 +01:00
Mathias Vorreiter Pedersen
4844c43f06 C++: Cleanup now that we're back to an abstract class. 2023-12-19 12:11:38 +01:00
Mathias Vorreiter Pedersen
937e0ee8d2 C++: Go back to abstract classes. 2023-12-19 12:10:57 +01:00
Michael Nebel
37b510cac0 C#: Add stubs for entity framework. 2023-12-19 11:52:59 +01:00
Mathias Vorreiter Pedersen
b6974d674c Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DebugPrinting.qll
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2023-12-19 11:47:46 +01:00
Michael Nebel
e12165707f C#: Delete the hand written stub System.Data.cs. 2023-12-19 11:37:33 +01:00
Michael Nebel
19a4cf3a7b C#: Update test cases that depends on System.Data.cs to use generated stubs. 2023-12-19 11:37:32 +01:00
Michael Nebel
7cb758a61b C#: Add stubs for System.Data.OleDb. 2023-12-19 11:37:32 +01:00
Mathias Vorreiter Pedersen
8230a90db6 C++: No need for another 'stars' predicate in 'PrintIRUtilities'. 2023-12-19 11:22:27 +01:00
Rasmus Wriedt Larsen
2305d55967 Merge pull request #15101 from yoff/python/update-InlineTaintTestPaths-to-new-api
Python: update to new API update is in a comment, so compilation never failed in CI.
2023-12-19 11:10:55 +01:00
Mathias Vorreiter Pedersen
9b25834771 C++: Use parameterized modules instead of abstract classes and predicates to handle debug printing. 2023-12-19 11:08:41 +01:00
Mathias Vorreiter Pedersen
501645920f C++: Move private stuff from 'DataFlowUtil' to public stuff 'DataFlowPrivate'. Also make 'PostUpdateNodeImpl' public in 'DataFlowUtil'. Sadly, this means that it's visible at the query level (as DataFlow::PostUpdateNodeImpl), but I've added a big INTERNAL QLDoc on it to make sure people don't use it. 2023-12-19 10:41:35 +01:00
Jeroen Ketema
180e752a23 C++: Update test after extractor changes
Also remove incorrect FP comment. clang does not support `#pragma hdrstop` in
its non-cl-emulation mode.
2023-12-18 23:30:13 +01:00
yoff
f50817e92a Merge pull request #15104 from RasmusWL/fewer-meta-queries
Python: Remove `@tags meta` from internal debug queries
2023-12-18 21:27:33 +01:00
yoff
e0c027f13c Merge pull request #14848 from hvitved/python/shared-type-tracking
Python: Adopt shared type tracking library
2023-12-18 21:14:42 +01:00
Mathias Vorreiter Pedersen
41c49ae05b Merge pull request #15136 from MathiasVP/fix-joins-in-use-after-free 2023-12-18 17:18:06 +01:00
Edward Minnix III
56921a6e21 Merge pull request #14040 from egregius313/egregius313/weak-hashing-properties
Java: Add support for algorithm names specified in `.properties` files to `java/potentially-weak-cryptographic-algorithm`
2023-12-18 09:38:58 -05:00
Tamás Vajk
d5f47a3d75 Merge pull request #15124 from tamasvajk/feature/telemetry/extraction-information
C#: Add telemetry query to report extractor information
2023-12-18 15:30:35 +01:00
Tamás Vajk
c5cf0641bf Merge pull request #15131 from tamasvajk/standalone/file-name
C#: Exclude not existing or problematic files from standalone extraction
2023-12-18 15:30:01 +01:00
Mathias Vorreiter Pedersen
d308bb40a0 Merge pull request #15132 from MathiasVP/fix-joins-in-isModifiableAtImpl
C++: Fix joins in `isModifiableAtImpl`
2023-12-18 15:01:36 +01:00
Mathias Vorreiter Pedersen
aafde4d18d C++: Fix joins in 'cpp/use-after-free'. 2023-12-18 14:49:09 +01:00
Tamas Vajk
f9c6d5e808 Ensure files are only enumerated once 2023-12-18 14:39:02 +01:00
Tamas Vajk
b14d26ab62 C#: Exclude not existing or problematic files from extraction 2023-12-18 14:10:56 +01:00
Tom Hvitved
a776132a10 Python: Deprecate more predicates 2023-12-18 13:05:17 +01:00
Tamas Vajk
1a8857dab8 Create problematic additional file in integration test 2023-12-18 12:32:24 +01:00
Mathias Vorreiter Pedersen
50b754b6c1 Merge pull request #15129 from MathiasVP/fix-joins-in-wrong-type-format-argument
C++: Fix joins in `cpp/wrong-type-format-argument`
2023-12-18 12:17:17 +01:00
Mathias Vorreiter Pedersen
f5c52ac496 C++: Fix joins in 'isModifiableAtImpl'. 2023-12-18 12:02:33 +01:00
Michael Nebel
d8fdba009a Merge pull request #15119 from michaelnebel/csharp/stubgenimprovements
C#: Escape method names in stub generation.
2023-12-18 11:35:29 +01:00
Michael Nebel
b10137c24c C#: Pick the first version number encountered. 2023-12-18 11:02:49 +01:00
Tamas Vajk
de1134ac48 C#: Add linux-only integration test 2023-12-18 10:55:11 +01:00
Mathias Vorreiter Pedersen
8ed9fbb295 Merge pull request #15123 from MathiasVP/fix-fps-in-double-free
C++: Fix FPs in `cpp/double-free` and `cpp/use-after-free`
2023-12-18 10:44:18 +01:00
Mathias Vorreiter Pedersen
e88c6888bc Merge pull request #15121 from MathiasVP/fix-joins-in-av-rule-145
C++: Fix joins in `AV Rule 145`
2023-12-18 10:42:46 +01:00
Tamas Vajk
3f843d820c Add telemetry query for known/unknown expression kinds 2023-12-18 10:02:32 +01:00
Mathias Vorreiter Pedersen
3897befbe2 C++: Fix joins in 'cpp/wrong-type-format-argument'. 2023-12-18 09:49:34 +01:00
Tony Torralba
9446249e94 Merge pull request #15012 from atorralba/atorralba/java/fix-missing-pinning-fp
Java: Fix FPs in Missing certificate pinning
2023-12-18 09:37:18 +01:00
Tony Torralba
0524289a73 Update java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql 2023-12-18 08:50:10 +01:00
Tom Hvitved
020a049d30 Merge pull request #15103 from hvitved/ruby/simple-pattern-flow
Ruby: Model simple pattern matching as value steps instead of taint steps
2023-12-18 08:49:11 +01:00
Mathias Vorreiter Pedersen
2eda5927d9 Merge pull request #15125 from geoffw0/launchoptions
Swift: Add more test cases for application(...launchOptions...).
2023-12-18 08:42:50 +01:00
Geoffrey White
1908575386 Swift: Add more test cases for launchOptions as a source. 2023-12-15 18:11:28 +00:00
Mathias Vorreiter Pedersen
ef916f0ba0 C++: Mitigate ODR violations. 2023-12-15 17:16:04 +00:00
Ed Minnix
09a0730491 QLdoc fix 2023-12-15 11:13:09 -05:00
Ed Minnix
02581a3850 Move class for getProperty method call to Properties.qll 2023-12-15 11:09:08 -05:00
Ed Minnix
73cb01fc89 Remove integration test (ported to query test)
The `.properties` file extractor has been enabled by default, so the
test about sources from `getProperty` calls can be ported to a query test.
2023-12-15 11:09:08 -05:00
Ed Minnix
fc53727b9d Bump change note date 2023-12-15 11:09:08 -05:00
Ed Minnix
8826eaf1a3 Move test case to query tests 2023-12-15 11:09:08 -05:00
Ed Minnix
afefccf8f7 Update change note 2023-12-15 11:09:08 -05:00
Ed Minnix
0d12981d6a Bump change note 2023-12-15 11:09:08 -05:00
Ed Minnix
078a33eecc Updated change note 2023-12-15 11:09:07 -05:00
Ed Minnix
1c3993e632 QLDocs 2023-12-15 11:09:07 -05:00
Ed Minnix
8e55ced288 Update test to use MaybeBrokenCryptoAlgorithm 2023-12-15 11:09:07 -05:00
Ed Minnix
83c6ece405 Move weak hashing into MaybeBrokenCryptoAlgorithm 2023-12-15 11:09:07 -05:00
Ed Minnix
fbc2a33597 Replace MethodAccess with MethodCall 2023-12-15 11:09:07 -05:00
Ed Minnix
c20ea1f629 Bump change note date 2023-12-15 11:09:07 -05:00
Ed Minnix
cb0ea350b5 Improve docs 2023-12-15 11:09:07 -05:00
Ed Minnix
0efca8200d Weak Hashing query wording 2023-12-15 11:09:07 -05:00
Ed Minnix
86b57a11ac Bump change note date 2023-12-15 11:09:07 -05:00
Ed Minnix
25fa8d5ae7 Move some logic to class 2023-12-15 11:09:07 -05:00
Ed Minnix
4ff6c1e2ea Test case
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2023-12-15 11:09:07 -05:00
Ed Minnix
93cf5b8eb9 Weak Hashing Property initial query 2023-12-15 11:09:07 -05:00
Tamas Vajk
e62d542e8f C#: Add telemetry query to report extractor information 2023-12-15 16:25:38 +01:00
Mathias Vorreiter Pedersen
82b9f1b31c C++: Accept test changes. 2023-12-15 14:57:31 +00:00
Mathias Vorreiter Pedersen
0543ed115e C++: Add barrier for array lookups in 'cpp/double-free' and 'cpp/use-after-free'. 2023-12-15 14:57:17 +00:00
Michael Nebel
38ae848b94 C#: Update generated stubs. 2023-12-15 15:50:08 +01:00
Michael Nebel
e69f0e3461 C#: Don't generate stubs for the record Clone method. 2023-12-15 15:41:59 +01:00
Mathias Vorreiter Pedersen
dc9c538fcc Merge pull request #15120 from MathiasVP/fix-joins-in-av-rule-79
C++: Fix joins in `cpp/resource-not-released-in-destructor`
2023-12-15 14:06:53 +00:00
Mathias Vorreiter Pedersen
1cbe01923d C++: Fix joins in 'AV Rule 145'. 2023-12-15 13:08:13 +00:00
Jeroen Ketema
3977689808 Merge pull request #15117 from jketema/buffer
C++: Only consider the maximum buffer size for badly bounded write
2023-12-15 13:46:09 +01:00
Alex Eyers-Taylor
8e92fcc08f CPP: Format Temporaries 2023-12-15 12:00:44 +00:00
Mathias Vorreiter Pedersen
2c5f65a241 C++: Drive-by cleanup: This case is redundant since a 'DestructorCall' is also a 'FunctionCall'. 2023-12-15 11:38:52 +00:00
Mathias Vorreiter Pedersen
ce326a0f79 C++: Fix joins. 2023-12-15 11:37:28 +00:00
Alexander Eyers-Taylor
c68d3c5983 Update cpp/ql/src/Security/CWE/CWE-416/Temporaries.qll
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2023-12-15 11:23:11 +00:00
Michael Nebel
f6af593b0b C#: Add a unit test for escaping method names. 2023-12-15 12:04:46 +01:00
Alex Eyers-Taylor
49e1467581 CPP: Fix handling of ternary operators in tempory queries and add tests. 2023-12-15 11:03:23 +00:00
Anders Schack-Mulligen
1ea1130271 Merge pull request #15062 from aschackmull/dataflow/deprecate-flowstatestring
Dataflow: Deprecate FlowStateString.
2023-12-15 11:59:04 +01:00
Michael Nebel
671692177e C#: Escape method names. 2023-12-15 11:34:06 +01:00
Jeroen Ketema
0b1b1be356 C++: Add change note 2023-12-15 11:13:52 +01:00
Erik Krogh Kristensen
16e53d3972 Merge pull request #15115 from erik-krogh/no-types-integration-test
JS: add integration test for the new extractor option to disable type extraction
2023-12-15 11:13:14 +01:00
Michael Nebel
d59b5a9647 Merge pull request #15100 from michaelnebel/csharp/stubsrefresh
C#: .NET8 Stubs update.
2023-12-15 10:46:43 +01:00
Jeroen Ketema
2065ecff66 C++: Only consider the maximum buffer size for badly bounded write 2023-12-15 10:46:13 +01:00
erik-krogh
a694928dd3 use the extractor option directly instead 2023-12-15 10:39:36 +01:00
erik-krogh
9c520778c7 Merge remote-tracking branch 'upstream/main' into no-types-integration-test 2023-12-15 10:38:05 +01:00
Jeroen Ketema
b29c886d9b Merge pull request #15107 from MathiasVP/better-tostring
C++: Produce a better `toString` for dataflow nodes with indirections
2023-12-15 10:19:53 +01:00
Michael Nebel
305e015948 C#: Update flowsummaries expected tests. 2023-12-15 10:02:02 +01:00
Michael Nebel
3ead21fb13 C#: Update options files. 2023-12-15 10:02:02 +01:00
Michael Nebel
588fe2792c C#: Update/Add some hand-written stubs for CWE-079 and CWE-611. 2023-12-15 10:02:02 +01:00
Michael Nebel
597a47b2d5 C#: Modify System.Web.cs manual stub to avoid overlap with generated stub. 2023-12-15 10:02:02 +01:00
Michael Nebel
0e6399e1cc C#: Make manual adjustments to the generated stubs. 2023-12-15 10:02:02 +01:00
Michael Nebel
8967a0996b C#: Update all generated stubs. 2023-12-15 10:02:02 +01:00
erik-krogh
ad4f464850 add warnOnImplicitThis 2023-12-15 09:55:30 +01:00
erik-krogh
9cc708b122 add integration test for the new extractor option to disable type extraction 2023-12-15 09:53:13 +01:00
Michael Nebel
5bc2183fc3 Merge pull request #15108 from michaelnebel/csharp/stubgenscripts
C#: Stub generator scripts.
2023-12-15 09:16:36 +01:00
yoff
72430438f3 Merge pull request #15109 from RasmusWL/consistency-cleanup
Python: Delete old copy of DataFlowImplConsistency.qll
2023-12-15 08:58:32 +01:00
Anders Schack-Mulligen
337e5e458c Update java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2023-12-15 08:48:50 +01:00
fossilet
795668ddaf Fix sphinx.add_lexer. 2023-12-15 09:58:46 +08:00
Erik Krogh Kristensen
a700aa4cde Merge pull request #15110 from rvermeulen/rvermeulen/xml-attr-data-flow-node
JavaScript: Add support for XML attributes in the data flow graph
2023-12-14 21:45:57 +01:00
Erik Krogh Kristensen
e838562591 Merge pull request #15105 from erik-krogh/fix-boolean-parse
JS: fix the parsing of boolean environment variables in the TypeScript extractor
2023-12-14 20:41:14 +01:00
Remco Vermeulen
133a243298 Add support for XML attributes in the data flow graph 2023-12-14 11:33:53 -08:00
Tom Hvitved
25a676ac6a Ruby: Model simple pattern matching as value steps instead of taint steps 2023-12-14 20:18:24 +01:00
Rasmus Wriedt Larsen
2a98a7e615 Python: Delete old copy of DataFlowImplConsistency.qll
We forgot to delete that file in https://github.com/github/codeql/pull/8457
2023-12-14 18:18:25 +01:00
Mathias Vorreiter Pedersen
7af6496a71 C++: Add change note. 2023-12-14 17:13:23 +00:00
Mathias Vorreiter Pedersen
04ca36f9b0 Merge pull request #15106 from geoffw0/revrevtest
Swift: Revert:Revert "Swift: CommonCrypto test cases for the BrokenCryptoAlgorithm query"
2023-12-14 15:56:46 +00:00
Mathias Vorreiter Pedersen
61e30b9ff8 C++: Accept more test changes. 2023-12-14 15:25:29 +00:00
Michael Nebel
82784b4364 C#: Add a script for generating stubs for all packages needed for testing. 2023-12-14 16:11:17 +01:00
Geoffrey White
7e6ff7c826 Swift: Disable the part of the test that triggers an extraction issue. 2023-12-14 15:04:48 +00:00
Mathias Vorreiter Pedersen
368f438754 C++: Add more QLDoc. 2023-12-14 14:49:48 +00:00
Geoffrey White
3193ceb3f9 Merge pull request #15052 from geoffw0/pointermodels
Swift: Expand models for UnsafePointer and friends
2023-12-14 14:46:48 +00:00
Mathias Vorreiter Pedersen
0c100eb122 C++: Accept test changes. 2023-12-14 14:44:58 +00:00
Mathias Vorreiter Pedersen
8a52565395 C++: Improve 'toString' on the most common dataflow nodes. 2023-12-14 14:44:42 +00:00
Anders Schack-Mulligen
7623432c76 Java: Remove/deprecate FlowStateString-based extension points. 2023-12-14 15:15:58 +01:00
Owen Mansel-Chan
9cb0bb2fc9 Merge pull request #15034 from github/dependabot/github_actions/actions/setup-go-5
Bump actions/setup-go from 4 to 5
2023-12-14 14:14:03 +00:00
Anders Schack-Mulligen
8ef4821f63 Python: Remove references to FlowStateString. 2023-12-14 15:05:33 +01:00
Anders Schack-Mulligen
a1068ce2f9 Dataflow: deprecate references 2023-12-14 15:05:33 +01:00
Anders Schack-Mulligen
07ad770437 Dataflow: Deprecate FlowStateString. 2023-12-14 15:05:33 +01:00
Geoffrey White
987cdff862 Revert "Revert "Swift: CommonCrypto test cases for the BrokenCryptoAlgorithm query""
This reverts commit a478980e48.
2023-12-14 13:56:35 +00:00
erik-krogh
0db788bb10 use direct string comparison instead, that doesn't crash on invalid values 2023-12-14 14:50:17 +01:00
erik-krogh
5e91b2f5bc fix the parsing of boolean environment variables in the TypeScript extractor 2023-12-14 14:40:10 +01:00
Rasmus Wriedt Larsen
36b635fb70 Python: Remove @tags meta from internal debug queries
These queries were great when evaluating coverage of the new call-graph compared with the old.

However, they are not useful to run as part of our DCA experiments.
2023-12-14 14:39:32 +01:00
Geoffrey White
36d0148aa1 Swift: Comment out lines that don't extract correctly right now. 2023-12-14 13:27:05 +00:00
Erik Krogh Kristensen
063f69c10e Merge pull request #15072 from erik-krogh/ts-various
JS: Various TypeScript extraction fixes.
2023-12-14 14:17:42 +01:00
Koen Vlaswinkel
7c141b9239 Merge pull request #15089 from github/koesie10/csharp-model-editor-generics
C#: Fix names of generic types/methods in model editor queries
2023-12-14 14:17:14 +01:00
Michael Nebel
3d012cd35f C#: Move the generator class to a helper file. 2023-12-14 14:11:59 +01:00
Michael Nebel
8343ce0754 C#: Re-factor the make_stubs_nuget script to more easily allow multiple nuget references. 2023-12-14 14:11:59 +01:00
Tom Hvitved
6fc9e6193a Add change note 2023-12-14 13:25:21 +01:00
Tom Hvitved
84aa9f17a0 Python/Ruby: Use SummaryTypeTracker from typetracking pack 2023-12-14 13:25:18 +01:00
Tom Hvitved
1e24de7e83 Copy SummaryTypeTracker.qll to typetracking pack 2023-12-14 13:22:48 +01:00
Tom Hvitved
3b1146bf98 Python: Adopt shared type tracking library 2023-12-14 13:22:44 +01:00
erik-krogh
72e99b5b9d rename extractor environment variable to CODEQL_EXTRACTOR_JAVASCRIPT_OPTION_SKIP_TYPES 2023-12-14 12:52:49 +01:00
Tom Hvitved
4776e9ccd2 Type tracking: Allow for a non-standard flowsTo predicate 2023-12-14 12:36:09 +01:00
Tom Hvitved
c8b4a215bc Merge pull request #14573 from hvitved/flow-summary-impl-param
Move `FlowSummaryImpl.qll` to `dataflow` pack
2023-12-14 12:24:15 +01:00
Rasmus Lerchedahl Petersen
0b6d47b8bc Python: update to new API
update is in a comment, so compilation
never failed in CI.
2023-12-14 11:56:05 +01:00
Tom Hvitved
8f0e0b6559 Merge pull request #15090 from hvitved/inline-flow-test-get-arg-string
InlineFlowTest: Allow for custom `getArgString`
2023-12-14 10:53:55 +01:00
Tamás Vajk
3487f9d143 Merge pull request #15070 from tamasvajk/standalone/exclusions
C#: Remove unneeded options and add support for `paths/paths-ignore` in standalone
2023-12-14 10:41:53 +01:00
Tom Hvitved
7da10e0013 Merge pull request #15095 from hvitved/dataflow/boolean-class
Data flow: Use `Boolean` class
2023-12-14 10:29:52 +01:00
Tamas Vajk
ee70de8879 Fix code review findings 2023-12-14 10:15:22 +01:00
Tom Hvitved
8fc6fb1ec0 Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2023-12-14 10:10:53 +01:00
Koen Vlaswinkel
96feb2c787 C#: Rename getMethodName to getEndpointName 2023-12-14 10:04:46 +01:00
Tom Hvitved
098afb935b Address more review comments 2023-12-14 09:48:45 +01:00
Tamas Vajk
728229e6e1 Fix code review findings 2023-12-14 09:44:20 +01:00
yoff
b78ceb61a3 Merge pull request #15099 from fossilet/fix-qll-typo
Fix typo in qll.
2023-12-14 09:43:26 +01:00
Chris Smowton
d884726490 Merge pull request #15098 from fossilet/fix-signature-doc
Fix typo.
2023-12-14 08:35:56 +00:00
fossilet
1cc2f073c4 Fix typo in qll. 2023-12-14 16:05:14 +08:00
Tom Hvitved
5a426d1800 Data flow: Use Boolean class 2023-12-14 09:04:16 +01:00
Michael Nebel
1653433f39 Merge pull request #15096 from github/workflow/coverage/update
Update CSV framework coverage reports
2023-12-14 08:51:34 +01:00
fossilet
9157dde4e2 Fix typo. 2023-12-14 15:35:13 +08:00
github-actions[bot]
c1325d798f Add changed framework coverage reports 2023-12-14 00:16:18 +00:00
Edward Minnix III
14a76278b8 Merge pull request #14802 from egregius313/egregius313/java/update-ql-integration-test
Java: Add `.properties` file references in integration tests
2023-12-13 18:40:03 -05:00
Ed Minnix
717e69ac0e Add properties file references 2023-12-13 16:54:55 -05:00
Paolo Tranquilli
307da3417d Merge pull request #15091 from github/redsun82/fix-cmake-bazel-version
Bazel/CMake: use bazelisk to use correct bazel version
2023-12-13 19:06:37 +01:00
Jeroen Ketema
4d922ddb0c Merge pull request #15092 from jketema/mb12
Merge back `rc/3.12` into main
2023-12-13 17:45:58 +01:00
Geoffrey White
e8f8aa266f Merge remote-tracking branch 'upstream/main' into pointermodels 2023-12-13 16:43:15 +00:00
Paolo Tranquilli
9e300a9906 Merge branch 'main' into redsun82/fix-cmake-bazel-version 2023-12-13 17:36:07 +01:00
Jeroen Ketema
25a1b0532e Merge pull request #15094 from github/revert-13870-commoncrypto1
Revert "Swift: CommonCrypto test cases for the BrokenCryptoAlgorithm query"
2023-12-13 17:21:44 +01:00
Mathias Vorreiter Pedersen
a478980e48 Revert "Swift: CommonCrypto test cases for the BrokenCryptoAlgorithm query" 2023-12-13 15:40:09 +00:00
Mathias Vorreiter Pedersen
5ddfb1f7c3 Merge pull request #15088 from MathiasVP/debug-mode-for-dataflow-printing
C++: Easier debugging of dataflow node `toString` output
2023-12-13 15:15:41 +00:00
Jeroen Ketema
99e65df6ce Merge remote-tracking branch 'upstream/rc/3.12' into mb12 2023-12-13 15:43:39 +01:00
Paolo Tranquilli
819fc52854 Bazel/CMake: use bazelisk to use correct bazel version 2023-12-13 15:32:06 +01:00
Mathias Vorreiter Pedersen
401ab3b035 C++: Fix 'isDebugMode'. It was computing 'isNotDebugMode' (oops). 2023-12-13 14:31:45 +00:00
Mathias Vorreiter Pedersen
fcc3113bfc C++: Privately import 'Node0ToString'. 2023-12-13 14:31:02 +00:00
Michael Nebel
b765ba387f Merge pull request #13110 from GeekMasher/csharp-aws
[CSharp] AWS Lambda Modelling
2023-12-13 15:14:58 +01:00
Geoffrey White
023d72b6fb Merge remote-tracking branch 'upstream/main' into pointermodels 2023-12-13 14:07:17 +00:00
Tamas Vajk
c870b0d4e9 Add more logging to the file filtering 2023-12-13 14:14:07 +01:00
Tamas Vajk
694be29311 Remove uneeded option from the help 2023-12-13 14:13:41 +01:00
Tom Hvitved
28a2d05cf8 InlineFlowTest: Allow for custom getArgString 2023-12-13 13:58:44 +01:00
Koen Vlaswinkel
e177f8783a C#: Share qualified name module for model editor queries 2023-12-13 13:48:44 +01:00
Koen Vlaswinkel
ea504cddd1 C#: Use correct names for generic types/methods in model editor queries 2023-12-13 13:48:23 +01:00
Michael Nebel
ffc36e4ccd Merge pull request #15085 from michaelnebel/csharp/telemetrycalls
C#: Telemetry should only count calls in source.
2023-12-13 13:46:16 +01:00
Koen Vlaswinkel
79f5a6acab C#: Add test model for generic method 2023-12-13 13:46:06 +01:00
Michael Nebel
3b9737fa88 C#: Update Amazon stubs to use .NET 8 as target framework. 2023-12-13 13:11:31 +01:00
Michael Nebel
c6a6a9f631 C#: Update Aws test files. 2023-12-13 13:07:29 +01:00
Michael Nebel
fa4f91988f C#: Add autogenerated stubs for Aws.Lambda.Core and Aws.Lambda.APIGatewayEvents. 2023-12-13 13:07:29 +01:00
Mathew Payne
f336ff0063 Add change notes 2023-12-13 13:07:28 +01:00
Mathew Payne
2e0ac264e7 feat: Add AWS Lambda logging 2023-12-13 13:07:28 +01:00
Mathew Payne
6c138ae485 feat: Add models and expected 2023-12-13 13:07:28 +01:00
Mathew Payne
2f5cb1ab29 feat: Add initial tests for AWS Lambda support 2023-12-13 13:07:28 +01:00
Mathew Payne
78a3749601 feat: Add Amazon Lambda testing stubs 2023-12-13 13:07:28 +01:00
Mathias Vorreiter Pedersen
45080ec9f0 C++: Create an abstract class to control debug 'toString' output for dataflow nodes. 2023-12-13 12:05:04 +00:00
Tamas Vajk
f2435f89f1 Simplify test setup 2023-12-13 13:03:23 +01:00
Tamas Vajk
993dd767ac C#: Add paths/paths-ignore support in standalone 2023-12-13 12:15:56 +01:00
Tamas Vajk
21229b93bf C#: Remove unneeded options from standalone extractor 2023-12-13 12:15:56 +01:00
Michael Nebel
8218f80154 C#: Base all telemetry tests on stubs. 2023-12-13 11:57:44 +01:00
Michael Nebel
57d5d71d03 C#: Only count calls in source code. 2023-12-13 11:57:32 +01:00
Michael Nebel
16e86134f3 Merge pull request #15087 from michaelnebel/csharp/stubgenrefreadonly
C#: Stub generator support for `ref readonly` parameters.
2023-12-13 11:46:45 +01:00
Owen Mansel-Chan
56507c2709 Merge pull request #15084 from github/dependabot/go_modules/go/extractor/extractor-dependencies-88d2ef26ea
Bump the extractor-dependencies group in /go/extractor with 1 update
2023-12-13 10:21:32 +00:00
Michael Nebel
b023338ed7 Merge pull request #15086 from michaelnebel/csharp/testusemorestubs
C#: Base more tests purely on stubs.
2023-12-13 11:19:38 +01:00
Michael Nebel
b7f4bfe719 C#: Add a unit test for stub generation of ref readonly parameters. 2023-12-13 11:09:57 +01:00
Michael Nebel
766baa9a50 C#: Add support for ref readonly parameters in the stub generator. 2023-12-13 11:09:57 +01:00
Tony Torralba
4cb53a76d6 Merge pull request #15082 from github/workflow/coverage/update
Update CSV framework coverage reports
2023-12-13 10:35:49 +01:00
Michael Nebel
35a615cac3 C#: Base the remoteflowsource test on stubs and update line numbers in expected output. 2023-12-13 10:07:57 +01:00
Michael Nebel
94d81b501b C#: Base the CWE-614 tests purely on stubs. 2023-12-13 10:07:57 +01:00
Michael Nebel
4fc8762444 C#: Base the asp/basic tests on stubs only. 2023-12-13 10:07:57 +01:00
Michael Nebel
0b39f1155e C#: Base the remaning CWE-1004 tests purely on stubs. 2023-12-13 10:07:57 +01:00
Michael Nebel
cdf6b28e13 C#: Base the modelgenerator/dataflow tests on stubs. 2023-12-13 10:07:56 +01:00
dependabot[bot]
dae1a5c70e Bump the extractor-dependencies group in /go/extractor with 1 update
Bumps the extractor-dependencies group in /go/extractor with 1 update: [golang.org/x/tools](https://github.com/golang/tools).

- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.16.0...v0.16.1)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: extractor-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-13 04:02:50 +00:00
github-actions[bot]
9b20665d75 Add changed framework coverage reports 2023-12-13 00:16:25 +00:00
Alexander Eyers-Taylor
236a6a1bce CPP: Apply suggestions from code review
Fix spelling in query id

Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2023-12-12 17:22:46 +00:00
Tony Torralba
bd8f35bef7 Java: Fix FPs in Missing certificate pinning
Local URIs should never require pinning
2023-12-12 18:02:12 +01:00
Alex Eyers-Taylor
136a77b86e CPP: Add change note for cpp/use-of-uniwue-pointer-after-lifetime-ends 2023-12-12 16:47:55 +00:00
Alex Eyers-Taylor
e9bc5a54ea CPP: Add query for detecting invalid uses of temporary unique pointers. 2023-12-12 16:22:20 +00:00
Tony Torralba
27be5ba14b Merge pull request #15073 from atorralba/atorralba/java/remove-invalid-ognl-sinks
Java: Remove invalid OGNL sinks
2023-12-12 16:52:31 +01:00
Owen Mansel-Chan
5675df842e Merge pull request #15054 from owen-mc/go/find-more-callees-for-captured-variables
Go: Also follow jump steps when looking for a callee source
2023-12-12 15:49:15 +00:00
Geoffrey White
609f92c7ac Merge pull request #13870 from geoffw0/commoncrypto1
Swift: CommonCrypto test cases for the BrokenCryptoAlgorithm query
2023-12-12 15:26:02 +00:00
Edward Minnix III
4d6521fd7a Merge pull request #13608 from egregius313/egregius313/weak-randomness
Java: Add Weak Randomness Query (CWE-330/338)
2023-12-12 09:40:11 -05:00
Tony Torralba
fad53a25c0 Update java/ql/lib/ext/struts2.model.yml
Co-authored-by: Anders Schack-Mulligen <aschackmull@users.noreply.github.com>
2023-12-12 14:58:47 +01:00
Mathias Vorreiter Pedersen
3dea467dcc Merge pull request #15047 from MathiasVP/add-puns-for-addresses-of-arguments
C++: Add `PostUpdateNode`s for addresses of outgoing arguments
2023-12-12 13:55:13 +00:00
Mathias Vorreiter Pedersen
412ea67ba0 Merge pull request #15075 from MathiasVP/print-data-flow-relevant-IR
C++: Add a `PropertyProvider` for only showing dataflow-relevant IR
2023-12-12 13:51:11 +00:00
Tom Hvitved
3c2336e40b Merge pull request #15074 from hvitved/dataflow/get-node-type-cached
Data flow: Use cached `nodeDataFlowType` instead of `getNodeType`
2023-12-12 14:49:41 +01:00
Mathias Vorreiter Pedersen
97f2be9b82 C++: Fix QLDoc. 2023-12-12 13:45:18 +00:00
yoff
a39eb5efc9 Merge pull request #15051 from yoff/python/slightly-improve-tarslip
Python: slightly improve tarslip logic
2023-12-12 14:43:43 +01:00
Mathias Vorreiter Pedersen
1ad0e6524e Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintDataFlowRelevantIR.qll 2023-12-12 13:15:36 +00:00
Mathias Vorreiter Pedersen
11386494b7 C++: Factor out the property provider which hides instructions and operands out of the 'LocalFlowPropertyProvider' class and into a separate class. 2023-12-12 13:04:31 +00:00
Tom Hvitved
a46964dfe8 Address review comments 2023-12-12 13:55:52 +01:00
Tom Hvitved
b3929e2375 Data flow: Use cached nodeDataFlowType instead of getNodeType 2023-12-12 13:46:39 +01:00
Tony Torralba
103110f9c2 Java: Remove invalid OGNL sinks
Fixes #15053
2023-12-12 13:39:51 +01:00
Alexander Eyers-Taylor
e87b3911dc Merge pull request #14910 from alexet/incorrect-scanf
CPP: Add query for detecteing incorrect error checking for scanf
2023-12-12 11:57:17 +00:00
Geoffrey White
f2e3391a33 Swift: Accept test regression. 2023-12-12 11:37:05 +00:00
erik-krogh
896432b646 add environment variable to skip extraction of types in TypeScript 2023-12-12 12:25:00 +01:00
Mathias Vorreiter Pedersen
4d430d5df0 Merge pull request #15037 from aschackmull/range/prunebounds
Rangeanalysis: Prune range calculation.
2023-12-12 11:18:26 +00:00
Mathias Vorreiter Pedersen
cec785c8cc C++: Respond to review comments. 2023-12-12 11:16:41 +00:00
Mathias Vorreiter Pedersen
f284fde93c C++: Update QLDoc. 2023-12-12 11:09:36 +00:00
Mathias Vorreiter Pedersen
a6104ad878 C++: Fix test annotations. 2023-12-12 11:06:18 +00:00
Rasmus Wriedt Larsen
42a6309f25 Merge pull request #15071 from github/RasmusWL/generate-code-scanning-query-list
Add @RasmusWL as CODEOWNER of a misc file
2023-12-12 10:53:11 +01:00
erik-krogh
cf31ef4960 make sure reset() is called when manually invoking the TS extractor, so environment-variables are read 2023-12-12 10:51:09 +01:00
Jeroen Ketema
611a177c3c Merge pull request #15066 from jketema/ql-test
C++: Update test for CLI changes
2023-12-12 10:36:57 +01:00
erik-krogh
c246a9c12c move TypeVarDepth further up, so its declared before it's used 2023-12-12 10:34:42 +01:00
erik-krogh
13a01e1545 fix a this reference
`this` didn't refer to anything specific, and it was in fact `undefined` in the context it was invoked. There was already a  `let typeTable = this;` further up (where `this` refers to the class instance), so I used `typeTable`.
2023-12-12 10:32:31 +01:00
Rasmus Wriedt Larsen
aa6a455ece Update CODEOWNERS 2023-12-12 10:31:36 +01:00
erik-krogh
ca95a6e9cf exclude all the lib.d.ts files when running the TS extractor directly
e.g. the `lib.es5.d.ts` file was not excluded
2023-12-12 10:29:09 +01:00
Tom Hvitved
9b043a10cc Merge pull request #15063 from hvitved/csharp/use-scratch-dir
C#: Use `CODEQL_EXTRACTOR_CSHARP_SCRATCH_DIR` instead of `Path.GetTempPath`
2023-12-12 08:16:04 +01:00
Owen Mansel-Chan
0fb58caa8c Update go/ql/lib/change-notes/2023-12-08-find-more-callees-for-captured-functions.md
Co-authored-by: Chris Smowton <smowton@github.com>
2023-12-11 20:42:48 +00:00
Edward Minnix III
06eef93f89 Docs review suggestions 2023-12-11 11:18:40 -05:00
Edward Minnix III
ce20c4ae03 Docs review suggestions
Co-authored-by: Ben Ahmady <32935794+subatoi@users.noreply.github.com>
2023-12-11 11:18:40 -05:00
Ed Minnix
7362158229 Fix test case 2023-12-11 11:18:40 -05:00
Ed Minnix
1271cd3348 Remove unnecessary crypto sinks 2023-12-11 11:18:40 -05:00
Ed Minnix
3ca039bc8f Rename to InsecureRandomness 2023-12-11 11:18:40 -05:00
Ed Minnix
6e70e6c85a Use pre-exisiting type for SecureRandom 2023-12-11 11:18:39 -05:00
Edward Minnix III
4678302edb Update query metadata
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2023-12-11 11:18:39 -05:00
Ed Minnix
bbf99375c7 Alter cookie sinks to instead focus on creation of a cookie 2023-12-11 11:18:39 -05:00
Ed Minnix
4bdf2b5e18 Bump change note date 2023-12-11 11:18:39 -05:00
Ed Minnix
b9d2a26e6e Move ESAPI models into the Weak Randomness query
These models don't need to apply to all queries. So instead they are
better suited to be within the weak randomness query itself.
2023-12-11 11:18:39 -05:00
Ed Minnix
7f3995f524 Remove extra encryption-iv models 2023-12-11 11:18:39 -05:00
Ed Minnix
7241e0920c Replace convertBytesToString with models 2023-12-11 11:18:39 -05:00
Ed Minnix
e9ca4a25d4 Update to new MethodCall name 2023-12-11 11:18:39 -05:00
Ed Minnix
a1e9564cc5 Add more sources 2023-12-11 11:18:39 -05:00
Ed Minnix
b8b2de2f3c Remove use of crypto-parameter sink kind 2023-12-11 11:18:39 -05:00
Ed Minnix
646254c9b2 Add credentials sinks from SensitiveApi 2023-12-11 11:18:39 -05:00
Ed Minnix
057a74d914 Remove unnused class 2023-12-11 11:18:39 -05:00
Ed Minnix
fb875f5095 More variety of test cases 2023-12-11 11:18:39 -05:00
Ed Minnix
ba3c38c226 Restrict addCookie to specific interface 2023-12-11 11:18:38 -05:00
Ed Minnix
dc3e4cd928 Refactored method accesses to the RandomDataSource library 2023-12-11 11:18:38 -05:00
Ed Minnix
ce7690b53f Make imports private 2023-12-11 11:18:38 -05:00
Edward Minnix III
bc0655573f Simplifications
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2023-12-11 11:18:38 -05:00
Ed Minnix
14fdfa4428 Add new sink kind and change note 2023-12-11 11:18:38 -05:00
Ed Minnix
0313f39229 Cryptographic sinks 2023-12-11 11:18:38 -05:00
Ed Minnix
b713efb711 Add ThreadLocalRandom.current as another source 2023-12-11 11:18:38 -05:00
Ed Minnix
bf0123d6ae Add org.apache.commons.lang.RandomStringUtils as a source 2023-12-11 11:18:38 -05:00
Ed Minnix
1daa83bf46 Add test cases 2023-12-11 11:18:38 -05:00
Ed Minnix
e69ff7b601 Move to library and add docs 2023-12-11 11:18:38 -05:00
Ed Minnix
9f986ca527 Add Weak Randomness Query 2023-12-11 11:18:38 -05:00
Edward Minnix III
8d724acb20 Merge pull request #15026 from egregius313/egregius313/java/dataflow/deprecate-old-dataflow-module-uses
Java: Deprecate or remove imports of dataflow library copies
2023-12-11 11:14:09 -05:00
Jeroen Ketema
8d2c72fc73 C++: Update test for CLI changes 2023-12-11 16:36:51 +01:00
Alexander Eyers-Taylor
c883ce8a5e Apply suggestions from code review
Co-authored-by: Ben Ahmady <32935794+subatoi@users.noreply.github.com>
2023-12-11 13:50:35 +00:00
Anders Schack-Mulligen
3bf6c0fe02 Rangeanalysis: Focus pre-bound calculation. 2023-12-11 14:07:10 +01:00
Anders Schack-Mulligen
c14d917a76 Rangeanalysis: Prune range calculation. 2023-12-11 14:07:10 +01:00
Anders Schack-Mulligen
58d463dd33 Rangeanalysis: Minor refactor for bound steps. 2023-12-11 14:07:10 +01:00
Anders Schack-Mulligen
73671b6da3 Rangeanalysis: Refactor base bounds. 2023-12-11 14:07:10 +01:00
Anders Schack-Mulligen
6b178fb64a Rangeanalysis: Preparatory refactor for bounds sharing. 2023-12-11 14:07:10 +01:00
Michael Nebel
7006d00702 Merge pull request #14892 from michaelnebel/csharp/dotnet8
C#: Use .NET 8
2023-12-11 13:53:35 +01:00
Michael Nebel
4b323cd7e0 Merge pull request #15050 from michaelnebel/csharp/defaultparamobject
C#: Default parameters for object using attributes.
2023-12-11 13:11:53 +01:00
Tom Hvitved
866f124a95 C#: Use CODEQL_EXTRACTOR_CSHARP_SCRATCH_DIR instead of Path.GetTempPath 2023-12-11 13:10:46 +01:00
Mathias Vorreiter Pedersen
97fc20cee9 Merge pull request #15064 from MathiasVP/swift-accept-test-changes-to-cleartext-transmission
Swift: Accept test changes
2023-12-11 11:13:38 +00:00
Óscar San José
693de5e6ff Merge pull request #15042 from github/dependabot/github_actions/actions/stale-9
Bump actions/stale from 8 to 9
2023-12-11 11:44:48 +01:00
Mathias Vorreiter Pedersen
2e4fe49d61 Swift: Accept test changes. 2023-12-11 10:41:07 +00:00
Rasmus Wriedt Larsen
419130be21 Merge pull request #15030 from yoff/python/remove-module-entry-definitions
Python: Remove control flow nodes for module entry definitions from the dataflow graph.
2023-12-11 11:40:17 +01:00
Mathias Vorreiter Pedersen
d8f53e5524 Merge pull request #14925 from geoffw0/flows
Swift: Imprecise Taint Flows
2023-12-11 10:06:01 +00:00
Michael Nebel
c8542e972e C#: Fix compiler warnings. 2023-12-11 10:57:44 +01:00
Michael Nebel
d3d594adaf C#: Update C# integration tests expected output. 2023-12-11 10:57:44 +01:00
Michael Nebel
3497b153d2 C#: Update integration tests to .NET 8. 2023-12-11 10:57:44 +01:00
Michael Nebel
1792942ce9 C#: Update tests that depends on .NET framework assemblies. 2023-12-11 10:57:44 +01:00
Michael Nebel
07a5ac31ae C#: Fixup tests. 2023-12-11 10:57:44 +01:00
Michael Nebel
e42afa3d3d C#: Adjustments to test cases. 2023-12-11 10:57:43 +01:00
Michael Nebel
09239ba804 C#: Update NuGet packages. 2023-12-11 10:57:43 +01:00
Michael Nebel
89f0abe3a0 C#: Update the target framework in the create extractor pack script. 2023-12-11 10:57:43 +01:00
Michael Nebel
9ab9f2b0e6 C#: Update all project files to use .NET 8 as target framework. 2023-12-11 10:57:43 +01:00
Michael Nebel
01c65e83a0 C#: Update the stub generator to .NET 8. 2023-12-11 10:57:43 +01:00
Michael Nebel
3e2afda202 C#: Update the create extractor pack action to .NET 8. 2023-12-11 10:57:43 +01:00
Michael Nebel
0df9dcb0fd C#: Update workflow files to also install .NET 8. 2023-12-11 10:57:43 +01:00
Geoffrey White
17cd22f9d0 Merge pull request #14972 from geoffw0/cryptoprimitives
C++: Experimental query for implementation of a cryptographic primitive
2023-12-11 09:47:46 +00:00
Mathias Vorreiter Pedersen
c6c487dd90 C++: Fix Code Scanning errors. 2023-12-11 09:35:44 +00:00
Mathias Vorreiter Pedersen
7faf286820 C++: Add more QLDoc to the 'is modifiable' predicates. 2023-12-11 09:29:59 +00:00
Tom Hvitved
cdf59e1e1d Ruby: Cache more predicates 2023-12-11 10:15:17 +01:00
Tom Hvitved
29a1cd110c Merge pull request #15041 from github/workflow/coverage/update
Update CSV framework coverage reports
2023-12-11 09:04:43 +01:00
github-actions[bot]
da48d81489 Add changed framework coverage reports 2023-12-11 00:16:52 +00:00
Tom Hvitved
f9dbf676a6 Java: Use FlowSummaryImpl from dataflow pack 2023-12-10 11:25:45 +01:00
Tom Hvitved
2d3f96f201 Swift: Use FlowSummaryImpl from dataflow pack 2023-12-10 11:25:44 +01:00
Tom Hvitved
35c654aa76 Go: Use FlowSummaryImpl from dataflow pack 2023-12-10 11:25:44 +01:00
Tom Hvitved
faaa558ed9 Python: Use FlowSummaryImpl from dataflow pack 2023-12-10 11:25:44 +01:00
Tom Hvitved
a2093c9aa2 C#: Use FlowSummaryImpl from dataflow pack 2023-12-10 11:25:43 +01:00
Tom Hvitved
28373e0fdf JS: Adapt to changes in shared code 2023-12-10 11:25:43 +01:00
Tom Hvitved
0e81577269 Ruby: Use FlowSummaryImpl from dataflow pack 2023-12-10 11:25:43 +01:00
Tom Hvitved
adc4455f09 Parameterize FlowSummaryImpl.qll 2023-12-10 11:11:05 +01:00
Tom Hvitved
41fa39eb7c Parameterize AccessPathSyntax.qll 2023-12-10 11:11:05 +01:00
Tom Hvitved
fd7e3454d6 Copy FlowSummaryImpl.qll to dataflow pack 2023-12-10 11:11:05 +01:00
Tom Hvitved
4fbd806d70 Copy AccessPathSyntax.qll to dataflow pack 2023-12-10 11:11:05 +01:00
Tom Hvitved
7819dcf0a7 Merge pull request #15043 from hvitved/ql/redundant-import
QL4QL: Improvements to `RedundantImport` query
2023-12-09 12:15:09 +01:00
Owen Mansel-Chan
2e2a82c237 Add change note 2023-12-08 23:33:58 +00:00
Owen Mansel-Chan
ab68c4e341 Update test 2023-12-08 23:29:44 +00:00
Owen Mansel-Chan
40b3598fd0 Also follow jump steps when looking for a callee source
This is needed because capturing a variable is a jump step
and we want to find a callee source for captured functions.
2023-12-08 18:44:14 +00:00
Geoffrey White
0133c659d5 Swift: Change note. 2023-12-08 16:53:38 +00:00
Geoffrey White
c2123f2c9b Swift: More detailed models for pointers. 2023-12-08 16:51:53 +00:00
Rasmus Lerchedahl Petersen
d9c0c8c26d Python: Update comment. 2023-12-08 17:32:23 +01:00
Rasmus Lerchedahl Petersen
2539e2ec1a Python: slightly improve tarslip logic 2023-12-08 17:18:25 +01:00
erik-krogh
e8f9e366d5 remove redundant imports for JS 2023-12-08 16:56:54 +01:00
Ed Minnix
1526da5929 Deprecation change note 2023-12-08 10:50:04 -05:00
Ed Minnix
aebbc7d4ab Add private imports to prevent compile warnings 2023-12-08 10:42:11 -05:00
Ed Minnix
1b8f3f3450 Deprecate or remove imports of dataflow library copies 2023-12-08 10:42:10 -05:00
Michael Nebel
fd12c3a3ba C#: Update expected test output. 2023-12-08 16:10:38 +01:00
Anders Schack-Mulligen
0618568cdc Merge pull request #15045 from aschackmull/java/fix-cp
Java: Fix accidental cartesian product.
2023-12-08 15:43:01 +01:00
Anders Schack-Mulligen
1ea2f89e27 Merge pull request #15046 from aschackmull/dataflow/deprecation-changenote
Dataflow: Add change note about deprecation.
2023-12-08 15:42:34 +01:00
Mathias Vorreiter Pedersen
90b06c2046 C++: Switch the source of use-after-free and double-free to be post-update nodes. 2023-12-08 14:41:29 +00:00
Michael Nebel
9aeba5063f C#: Use cast expressions for object defaults. 2023-12-08 15:37:12 +01:00
Mathias Vorreiter Pedersen
5bb2144c80 C++: Add field-flow through addresses of fields 2023-12-08 14:13:01 +00:00
Michael Nebel
6c30f6a748 C#: Add some test cases and update (incorrect) expected output. 2023-12-08 15:09:35 +01:00
Jeroen Ketema
db6b1e5f5e Merge pull request #14912 from jketema/dep-userinput
C++: Deprecate `isUserInput`, `userInputArgument`, and `userInputReturned`
2023-12-08 15:04:23 +01:00
Alex Eyers-Taylor
da5c2d9bad CPP: Use guard libraries to find equalities with zero. 2023-12-08 13:30:30 +00:00
Alexander Eyers-Taylor
df32e9556c Update cpp/ql/src/change-notes/2023-12-04-incorrectly-checked-scanf.md
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2023-12-08 13:29:13 +00:00
Anders Schack-Mulligen
64eb4ff753 Merge pull request #14983 from aschackmull/dataflow/deprecate-old-api
Data Flow: Deprecate old data flow api.
2023-12-08 14:27:25 +01:00
Anders Schack-Mulligen
75d8da9007 Dataflow: Add change note about deprecation. 2023-12-08 14:25:20 +01:00
Jeroen Ketema
c6b0a2363a C++: Add change note 2023-12-08 13:31:32 +01:00
Anders Schack-Mulligen
7ee3068fe7 Java: Fix accidental cartesian product. 2023-12-08 13:27:05 +01:00
Jeroen Ketema
5165999e9e C++: Deprecate isUserInput, userInputArgument, and userInputReturned 2023-12-08 13:21:31 +01:00
Mathias Vorreiter Pedersen
30c67ba6e7 Merge pull request #15040 from MathiasVP/fewer-dataflow-branches
C++: Fix dataflow inconsistencies
2023-12-08 12:14:49 +00:00
Harry Maclean
1dc0a063b0 Merge pull request #14679 from hmac/hmac-model-editor-ruby
Ruby: Experimental model editor support
2023-12-08 11:03:38 +00:00
Mathias Vorreiter Pedersen
90a62b27f5 Merge branch 'main' into fewer-dataflow-branches 2023-12-08 10:35:33 +00:00
Geoffrey White
6a48e6ed5e Merge pull request #15038 from geoffw0/mmmmodels
Swift: Model Manual Memory Management closure functions and withMemoryRebound variants
2023-12-08 10:25:58 +00:00
Mathias Vorreiter Pedersen
7b83947383 Merge branch 'main' into fewer-dataflow-branches 2023-12-08 09:30:01 +00:00
Mathias Vorreiter Pedersen
1c73d43b4f C++: Accept more test changes. 2023-12-08 09:29:48 +00:00
Tom Hvitved
0361b2e6e8 QL4QL: Improvements to RedundantImport query 2023-12-08 10:19:04 +01:00
Harry Maclean
199c6b224d Ruby: fix warnings 2023-12-08 09:16:17 +00:00
Jeroen Ketema
9a555ba16e Merge pull request #14909 from jketema/rm-dtt
C++: Remove `DefaultTaintTracking` library
2023-12-08 10:08:55 +01:00
dependabot[bot]
e822fe975d Bump actions/stale from 8 to 9
Bumps [actions/stale](https://github.com/actions/stale) from 8 to 9.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v8...v9)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-08 03:10:16 +00:00
Mathias Vorreiter Pedersen
e648058d30 C++: Accept test changes. 2023-12-07 23:11:28 +00:00
Mathias Vorreiter Pedersen
d6871c7cf9 C++: Merge 'PostUpdateFieldNode' and 'IndirectArgumentOutNode' into a single IPA branch. 2023-12-07 23:11:28 +00:00
Geoffrey White
ba6d3484f5 Swift: Add more tests of pointer methods. 2023-12-07 18:09:34 +00:00
Chuan-kai Lin
96b793a877 Merge pull request #15032 from github/post-release-prep/codeql-cli-2.15.4
Post-release preparation for codeql-cli-2.15.4
2023-12-07 09:23:32 -08:00
Geoffrey White
801878bff2 Swift: I believe flow through withUnsafeMutableBytes should always be taint flow, as it changes the type of elements to bytes. 2023-12-07 16:42:35 +00:00
Geoffrey White
ea68af8b7f Swift: Change note. 2023-12-07 16:42:34 +00:00
Geoffrey White
8818b3d22d Swift: Model withMemoryRebound, assumingMemoryRebound, bindMemory. 2023-12-07 16:03:01 +00:00
Geoffrey White
db3dfdc9a0 Swift: Model Manual Memory Management closure functions. 2023-12-07 15:55:00 +00:00
Michael Nebel
2e6e2eabf2 Merge pull request #15036 from michaelnebel/csharp/intptrdefaultssimple
C#: Parameter defaults for `nint` and `nuint` in compiled code.
2023-12-07 16:20:41 +01:00
Geoffrey White
1de9919193 Swift: Test Manual Memory Management closure functions. 2023-12-07 15:10:41 +00:00
Harry Maclean
1b29ed2a81 Ruby: Address review comments 2023-12-07 14:31:27 +00:00
Harry Maclean
79a83ec74b Ruby: elaborate placeholder query 2023-12-07 14:26:15 +00:00
Tamás Vajk
51adcf5e10 Merge pull request #15010 from tamasvajk/fix/stringbuilder-interpolation
C#: Support interpolated strings in `StringBuilder.Append`
2023-12-07 15:25:44 +01:00
Anders Schack-Mulligen
9fafa973d8 C++: Remove irrelevant test. 2023-12-07 14:13:42 +01:00
Tamas Vajk
75fa67726e Fix models to support fluent chaining 2023-12-07 14:10:16 +01:00
Michael Nebel
d9c6d4e6cb C#: Update Parameters expected output. 2023-12-07 13:14:24 +01:00
Michael Nebel
aac3ec81f2 C#: Add generated cast expression for nuint and nint parameter defaults. 2023-12-07 13:14:24 +01:00
Geoffrey White
32fdf4fc9f Merge pull request #15007 from geoffw0/sensitivekeytests
Swift: Add some tests and model SecKeyCopyExternalRepresentation
2023-12-07 10:50:13 +00:00
Tamas Vajk
e0c9be371f Add change note 2023-12-07 10:57:18 +01:00
Tamas Vajk
89df59a083 C#: Add missing models and fix interpolated string flow into StringBuilder 2023-12-07 10:56:59 +01:00
Geoffrey White
028326abad Swift: Correct US spellings. 2023-12-07 09:54:01 +00:00
Tamas Vajk
2c624c23ed Add test cases for missing flow with interpolated strings and StringBuilder 2023-12-07 10:32:01 +01:00
Tamas Vajk
9f24b026fb C#: Move StringBuilder dataflow tests to separate file 2023-12-07 10:31:50 +01:00
Tamás Vajk
3431fcf9af Merge pull request #15025 from tamasvajk/feature/change-stringbuilder-modeling
C#: Change `StringBuilder` flow models to not use `Element` access path
2023-12-07 10:29:54 +01:00
Tamas Vajk
c1db689f2f Fix expected test results 2023-12-07 09:59:33 +01:00
Tamas Vajk
669a0c6827 Fix StringBuilder.ToString summaries 2023-12-07 09:21:27 +01:00
Tamás Vajk
a8bd6b8cb1 Merge pull request #15024 from tamasvajk/fix/interpolated-strings-stubs
C#: Add interpolated string handler attributes to generated stubs
2023-12-07 08:18:08 +01:00
dependabot[bot]
3d7ab2e0b0 Bump actions/setup-go from 4 to 5
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-07 03:43:13 +00:00
github-actions[bot]
92af5f5386 Post-release preparation for codeql-cli-2.15.4 2023-12-06 22:59:22 +00:00
Rasmus Lerchedahl Petersen
263c0aade7 Python: adjust test expectations
mostly removing of nodes from the graph.
One result lost:
```
check("submodule.submodule_attr", submodule.submodule_attr, "submodule_attr", globals()) #$ MISSING:prints=submodule_attr
```
2023-12-06 23:00:51 +01:00
Mathias Vorreiter Pedersen
04c2ce97fd Merge pull request #15027 from jketema/more-exit
C++: Also support the `__noreturn__` attribute in `exits`
2023-12-06 21:48:26 +00:00
Rasmus Lerchedahl Petersen
8c5ca3f564 Python: remove control flow nodes
for module entry definitions from the dataflow graph.
2023-12-06 21:47:03 +01:00
Robert Marsh
1087087acb Merge pull request #14570 from rdmarsh2/rdmarsh2/swift/extract-pattern-types
Swift: extract types for patterns
2023-12-06 14:11:53 -05:00
Geoffrey White
366a9f1b7e Swift: Convert unsafepointer.swift test to use labelled sources. 2023-12-06 18:57:30 +00:00
Jeroen Ketema
af1da1e9ae C++: Also support the __noreturn__ attribute in exits
Observed this attribute while working on coding standards test regression
when replacing Guards by IRGuards.
2023-12-06 18:08:39 +01:00
Mathias Vorreiter Pedersen
1bc6f88f58 Merge pull request #14992 from jketema/ir-guards-replacement
C++: replace Guards with IRGuards
2023-12-06 15:55:22 +00:00
Tamas Vajk
eeabb81973 Adjust expected test files 2023-12-06 16:00:43 +01:00
Tamas Vajk
a705f6dc0d C#: Change StringBuilder flow models to not use Element access path 2023-12-06 15:54:34 +01:00
Ian Lynagh
c1cc441da7 Merge pull request #15023 from igfoo/igfoo/df-wrapper
Kotlin: Fix dataflow with Array.set wrappers
2023-12-06 14:48:54 +00:00
Tamas Vajk
50b7ab8448 C#: Add interpolated string handler attributes to generated stubs 2023-12-06 15:40:48 +01:00
Tamás Vajk
faa63dda8b Merge pull request #14994 from tamasvajk/standalone/framework-assembly-reshuffle
C#: Only consider latest version of dotnet framework flavors
2023-12-06 14:54:11 +01:00
Ian Lynagh
fc11a87882 Kotlin: Fix dataflow with Array.set wrappers 2023-12-06 12:19:46 +00:00
Ian Lynagh
7fc7b96ed7 Kotlin: Add a test for dataflow with an Array.set wrapper 2023-12-06 12:19:25 +00:00
Ian Lynagh
49c188e612 Merge pull request #15009 from igfoo/igfoo/qual
Docs: DataFlow: Add a missing qualifier
2023-12-06 12:10:56 +00:00
Jeroen Ketema
edf178696d C++: accept test changes for IR Guards replacement 2023-12-06 12:47:20 +01:00
Robert Marsh
88073a5fb2 C++: change note for IRGuards replacing Guards 2023-12-06 12:47:20 +01:00
Robert Marsh
172445f5e7 C++: replace Guards with IRGuards 2023-12-06 12:47:20 +01:00
Jeroen Ketema
db1dc6fa2c Merge pull request #15021 from jketema/ir-guards-unreached-fix
C++: Fix handling of unreached instructions in IRGuards
2023-12-06 12:46:09 +01:00
Paolo Tranquilli
db0fc3775a Merge pull request #15004 from github/alexdenisov/fix-swift-autobuilder-bug
Swift: fix autobuilder bug when Xcode failure breaks the whole autobuild process
2023-12-06 11:29:26 +01:00
Mathias Vorreiter Pedersen
9fa20f5f39 Merge pull request #14799 from MathiasVP/solve-modify-copy-problem
DataFlow: Add language-specific predicate for ignoring steps in flow-through calculation
2023-12-06 09:55:34 +00:00
Jeroen Ketema
4390e4cad3 C++: Fix handling of unreached instructions in IRGuards 2023-12-06 10:23:27 +01:00
Jeroen Ketema
d6e30cd828 C++: Add test showing unreachable instructions give spurious blocks in IRGuards 2023-12-06 10:23:27 +01:00
Tamas Vajk
efa7408491 C#: Use latest asp.net core/windows desktop framework DLLs from nuget folder 2023-12-06 10:17:02 +01:00
Geoffrey White
ff8b796731 Merge pull request #14692 from geoffw0/webview3
Swift: Simplify AdoptsWkNavigationDelegate in WebView.qll.
2023-12-06 09:11:33 +00:00
Jeroen Ketema
49a4306514 Merge pull request #15015 from jketema/exit
C++: Add `_Exit` to the list of exiting (non-returning) functions
2023-12-06 10:07:55 +01:00
Geoffrey White
4cec14657e Merge pull request #14853 from geoffw0/logsinks
Swift: More sinks for swift/cleartext-logging
2023-12-06 09:00:26 +00:00
Owen Mansel-Chan
aad847497b Merge pull request #14962 from owen-mc/go/improve-tests-incorrect-integer-conversion
Go: Improve tests for Incorrect Integer Conversion
2023-12-06 07:40:00 +00:00
Nora Dimitrijević
6d24eb4814 Merge pull request #14897 from d10c/d10c/relax-cpp-dbscheme
C++: Relax the dbscheme for `link_targets/2`
2023-12-05 23:27:03 +01:00
Nora Dimitrijević
66c0a4af5a Upgrade/downgrade script 2023-12-05 22:03:40 +01:00
Nora Dimitrijević
0307354d6e Relax the C++ dbscheme for link_targets/2 2023-12-05 22:03:40 +01:00
Chuan-kai Lin
5b62c0cb53 Merge pull request #15016 from github/revert-15003-dependabot/github_actions/actions/labeler-5
Revert "Bump actions/labeler from 4 to 5"
2023-12-05 12:43:16 -08:00
Chuan-kai Lin
ba57a0363c Revert "Bump actions/labeler from 4 to 5" 2023-12-05 12:09:56 -08:00
Jeroen Ketema
696cbeae5c C++: Add _Exit to the list of exiting (non-returning) functions 2023-12-05 20:33:43 +01:00
Tom Hvitved
dde83b6415 Merge pull request #14709 from hvitved/ruby/shared-type-tracking
Ruby: Adopt shared type tracking library
2023-12-05 20:12:06 +01:00
Ian Lynagh
2c625e34b5 Merge pull request #15008 from igfoo/igfoo/kot-arr-taint
Kotlin: Track taint through Array.get/set
2023-12-05 18:30:21 +00:00
Geoffrey White
521d98ed8d C++: Make the encryption words a tiny bit more flexible. 2023-12-05 18:03:17 +00:00
Geoffrey White
e95098f61f C++: Add 'experimental' tag. 2023-12-05 18:03:11 +00:00
Geoffrey White
cde975dc24 C++: Add even more test cases. 2023-12-05 18:02:51 +00:00
Geoffrey White
2f0be40f37 C++: Exclude results in some common libraries. 2023-12-05 18:00:00 +00:00
Geoffrey White
965d131b5a C++: Add more test cases. 2023-12-05 17:59:26 +00:00
Geoffrey White
fb02e996d4 C++: Address QL-for-QL comments. 2023-12-05 17:58:35 +00:00
Geoffrey White
c83cfe4936 C++: Make output clearer in cases where the function name is a macro expansion (I've seen this more than once). 2023-12-05 17:58:22 +00:00
Geoffrey White
3c6f318cb2 C++: Add query tests. 2023-12-05 17:54:50 +00:00
Taus
a09078a5ca Merge pull request #14777 from yoff/python/remove-ssa-nodes-from-dataflow-graph
Python: remove EssaNodes
2023-12-05 18:10:27 +01:00
Henti Smith
33a0de07b6 Merge pull request #15002 from github/dependabot/github_actions/actions/setup-dotnet-4
Bump actions/setup-dotnet from 3 to 4
2023-12-05 15:35:00 +00:00
Henti Smith
0232cd032c Merge pull request #15003 from github/dependabot/github_actions/actions/labeler-5
Bump actions/labeler from 4 to 5
2023-12-05 15:34:47 +00:00
Tamas Vajk
1b37c66bf8 C#: Only consider latest version of dotnet framework flavors 2023-12-05 16:33:42 +01:00
Michael Nebel
9390b48228 C#: Add (U)IntPtr parameter default test cases. 2023-12-05 16:29:16 +01:00
Ian Lynagh
27f99acb2e Docs: DataFlow: Add a missing qualifier 2023-12-05 14:51:15 +00:00
Geoffrey White
e60dc9a9ed Swift: Use the PostUpdateNode. 2023-12-05 14:48:46 +00:00
Ian Lynagh
8ea155ef24 Kotlin: Add changenote 2023-12-05 14:48:02 +00:00
Ian Lynagh
babf1d6648 Kotlin: Track Kotlin's Array.set when tracking taint 2023-12-05 14:42:45 +00:00
Ian Lynagh
124487c57c Kotlin: Add more taint tests 2023-12-05 14:42:45 +00:00
Ian Lynagh
821b4c727e Kotlin: Add Array.get(_) support to taint tracking 2023-12-05 14:41:32 +00:00
Ian Lynagh
9953794101 Kotlin: Add an extra test case for Kotlin array taint 2023-12-05 14:41:32 +00:00
Jeroen Ketema
30e5e74a78 Merge pull request #15005 from jketema/ir-guards-ternary-fix
C++: Fix IRGuards ternary behaviour
2023-12-05 15:04:56 +01:00
Henti Smith
f66133e29e Merge branch 'main' into dependabot/github_actions/actions/labeler-5 2023-12-05 14:03:25 +00:00
Henti Smith
1d9cd0a73b Merge branch 'main' into dependabot/github_actions/actions/setup-dotnet-4 2023-12-05 14:03:23 +00:00
Tom Hvitved
c6e805faef Ruby: Add more deprecation comments 2023-12-05 14:57:15 +01:00
Geoffrey White
11d582db51 Swift: Change note. 2023-12-05 13:35:44 +00:00
Geoffrey White
5095031110 Swift: Model SecKeyCopyExternalRepresentation as an explicit sensitive data source. 2023-12-05 13:35:44 +00:00
Geoffrey White
1d903c56ad Swift: Add a test with SecKeyCopyExternalRepresentation. 2023-12-05 13:35:44 +00:00
Michael Nebel
e6a5c50ebc Merge pull request #14953 from rpmrmartin/issue/14952
C#: Fix a URL redirection from remote source false positive
2023-12-05 13:02:56 +01:00
Mathias Vorreiter Pedersen
8ce4bbec33 Merge pull request #14867 from MathiasVP/reduce-duplication-from-operators
C++: Reduce duplication from crement operations
2023-12-05 11:57:48 +00:00
Ian Lynagh
70ff59eee1 Merge pull request #14997 from igfoo/igfoo/locs
Kotlin: Accept some location changes in test-kotlin2/library-tests/vararg
2023-12-05 11:18:27 +00:00
Jeroen Ketema
4d702e2eee C++: Fix IRGuards ternary behaviour 2023-12-05 12:17:46 +01:00
Jeroen Ketema
d84961571b C++: Add IRGuards test that shows that ternary behaviour is not quite correct 2023-12-05 12:16:01 +01:00
Mathias Vorreiter Pedersen
2908acfb52 Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2023-12-05 11:00:17 +00:00
Mathias Vorreiter Pedersen
db0d203eb4 Merge branch 'main' into solve-modify-copy-problem 2023-12-05 09:43:17 +00:00
Mathias Vorreiter Pedersen
a8020f4f78 C++: Add barrier to prevent duplication. 2023-12-05 09:14:23 +00:00
Tom Hvitved
71d09b75fb Merge pull request #14990 from hvitved/csharp/more-nullness-tests
C#: Add a few more `is (not) null` tests
2023-12-05 10:14:13 +01:00
Michael Nebel
8dcdda6d21 C#: Address review comments. 2023-12-05 10:08:06 +01:00
Alex Denisov
8f3d31818c Swift: fix autobuilder bug when Xcode failure breaks the whole autobuild process 2023-12-05 09:58:33 +01:00
Tony Torralba
07b76ee444 Merge pull request #15000 from github/workflow/coverage/update
Update CSV framework coverage reports
2023-12-05 08:54:20 +01:00
Tamás Vajk
b06113a21e Merge pull request #14991 from tamasvajk/standalone/prefer-assembly-version-over-netcore-version
C#: Prefer assembly version over netcore version in conflict resolution
2023-12-05 08:49:08 +01:00
dependabot[bot]
eb08a508c9 Bump actions/labeler from 4 to 5
Bumps [actions/labeler](https://github.com/actions/labeler) from 4 to 5.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-05 03:33:07 +00:00
dependabot[bot]
4d68beffe0 Bump actions/setup-dotnet from 3 to 4
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3 to 4.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-05 03:33:03 +00:00
github-actions[bot]
48c15035b9 Add changed framework coverage reports 2023-12-05 00:16:34 +00:00
Robert Marsh
e9507b98ef Swift: remove spurious stats file 2023-12-04 21:30:12 +00:00
Geoffrey White
a5dd4a4e2a Swift: More tests of keys as sensitive data. 2023-12-04 19:05:15 +00:00
Alex Eyers-Taylor
7706ac9f10 CPP: Fix changenote location 2023-12-04 18:50:25 +00:00
Alexander Eyers-Taylor
2e92689810 CPP: Apply suggestions from code review of incorrect scanf check
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2023-12-04 18:32:03 +00:00
Mathias Vorreiter Pedersen
6dd941ee20 Merge pull request #14996 from jketema/toctou-test
C++: Fix `chmod` prototype in toctou test and additional test
2023-12-04 17:42:52 +00:00
Owen Mansel-Chan
570538b4ec Merge pull request #14938 from owen-mc/go/improve-test-unhandled-close-writable-handle
Go: improve test unhandled close writable handle
2023-12-04 16:56:09 +00:00
Jeroen Ketema
7f1bd499ce C++: Add test annotation 2023-12-04 17:53:08 +01:00
Mathias Vorreiter Pedersen
d9d36ff213 C++: Fix Code Scanning errors. 2023-12-04 16:53:03 +00:00
Rasmus Lerchedahl Petersen
9e1c818db6 Python: address review comments 2023-12-04 17:49:26 +01:00
Ian Lynagh
1aa1698f44 Kotlin: Accept some location changes in test-kotlin2/library-tests/vararg 2023-12-04 16:44:38 +00:00
yoff
f5c176bd12 Apply suggestions from code review
Co-authored-by: Taus <tausbn@github.com>
2023-12-04 17:41:00 +01:00
Mathias Vorreiter Pedersen
03b77dbf2a C++: Make 'node.asExpr()' behave as 'node.asDefinition()' in void contexts. 2023-12-04 16:38:13 +00:00
Jami
651653998c Merge pull request #14913 from jcogs33/jcogs33/unsafe-url-forward_path-inj-related_cve-2019-3799
Java: add Spring models
2023-12-04 10:18:50 -05:00
Jeroen Ketema
3e2397a3d1 C++: Fix chmod prototype in toctou test and additional test 2023-12-04 16:15:44 +01:00
Tamas Vajk
267125a65e Adjust comment on OrderAssemblyInfosByPreference method 2023-12-04 15:21:30 +01:00
Rasmus Wriedt Larsen
c952f6a648 Python: Update rest of tests to new dataflow lib
I had missed these originally, since I had just fixed the ones that were
highlighted in the actions logs, thinking they had covered everything :(
2023-12-04 14:49:40 +01:00
Tamas Vajk
db22478a47 Fix expected test files 2023-12-04 14:39:20 +01:00
Rasmus Lerchedahl Petersen
e091ae84ab Merge branch 'main' of https://github.com/github/codeql into python/remove-ssa-nodes-from-dataflow-graph 2023-12-04 14:05:40 +01:00
Alex Eyers-Taylor
f3f53570a4 CPP: Fix metadata and add a change-note. 2023-12-04 12:19:31 +00:00
Michael Nebel
2fc7e51a5b C#: Only include source code (and not stubs) in the remote flow source test. 2023-12-04 13:10:10 +01:00
Tom Hvitved
46531e653d C#: Deprecate OnAppendCookieTrackingConfig 2023-12-04 12:36:57 +01:00
Rasmus Wriedt Larsen
4dd3ea3798 Python: Update tests to new dataflow lib
Avoids some deprecation warnings :)
2023-12-04 12:36:57 +01:00
Anders Schack-Mulligen
67f0529cda Dataflow: Sync. 2023-12-04 12:36:57 +01:00
Anders Schack-Mulligen
fd920b8585 Java: Deprecate old data flow api. 2023-12-04 12:36:57 +01:00
Mathias Vorreiter Pedersen
359b15bb60 C++: Fix FP by special-casing compound assignments in 'asExprInternal'. 2023-12-04 11:29:51 +00:00
Tom Hvitved
84cba21a6c C#: Add a few more is (not) null tests 2023-12-04 12:22:47 +01:00
Mathias Vorreiter Pedersen
ce28c9b485 C++: Add more CWE-119 testcases with compound assignments instead of increments. 2023-12-04 11:22:16 +00:00
Michael Nebel
b9833fc97e C#: Updated expected test output. 2023-12-04 12:02:51 +01:00
Michael Nebel
d160890aca C#: Re-factor to avoid multiple explicit casts. 2023-12-04 12:02:34 +01:00
Michael Nebel
6807fd1569 C#: Add some stubs, a testcase and update the expected output without based on main. 2023-12-04 11:53:09 +01:00
Mathias Vorreiter Pedersen
60204574b6 Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2023-12-04 10:35:07 +00:00
Mathias Vorreiter Pedersen
1198d23b96 Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2023-12-04 10:35:00 +00:00
Mathias Vorreiter Pedersen
5a12a0ad62 Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2023-12-04 10:34:46 +00:00
Mathias Vorreiter Pedersen
09117d3869 Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2023-12-04 10:34:32 +00:00
Tamas Vajk
6f82e63461 C#: Prefer assembly version over netcore version in conflict resolution 2023-12-04 11:08:33 +01:00
Geoffrey White
b0514de094 C++: Add cpp/crypto-primitive query to experimental. 2023-11-30 15:03:03 +00:00
Robert Marsh
ba250140a8 Swift: fix an incorrect merge conflict resolution 2023-11-30 14:55:14 +00:00
Mathias Vorreiter Pedersen
3a61dd095c C++: Add change note. 2023-11-30 14:39:57 +00:00
Mathias Vorreiter Pedersen
c1561e8675 Merge branch 'main' into reduce-duplication-from-operators 2023-11-30 14:30:50 +00:00
Mathias Vorreiter Pedersen
43932b61a8 C++: Add more comments. 2023-11-30 14:20:00 +00:00
Owen Mansel-Chan
d52b23db8e Improve tests for Incorrect Integer Conversion
We changed the test query when the query was changed so that the
comments in the test file would stay the same.
I've reverted the test query and updated the comments in the test file.
This avoids problems in the branch switching to use-use flow.
2023-11-30 11:58:10 +00:00
Owen Mansel-Chan
e958a75223 Add comments indicating whether results are expected at new calls 2023-11-30 11:48:10 +00:00
Jami Cogswell
7e869b9cd1 Java: add change note 2023-11-29 16:48:57 -05:00
Robert Marsh
0dc4a68ffb Swift: fix typo in change note
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
2023-11-29 21:04:09 +00:00
Robert Marsh
81d2780adb Swift: changenote for pattern types 2023-11-29 21:04:09 +00:00
Robert Marsh
30caf2130e Swift: autoformat a test 2023-11-29 21:04:09 +00:00
Robert Marsh
16e6e8845c Swift: tests for pattern types 2023-11-29 21:04:08 +00:00
Robert Marsh
ade4809d9b Swift: upgrade/downgrade for pattern types 2023-11-29 21:04:05 +00:00
Robert Marsh
3492b4820a Swift: extract types for patterns 2023-11-29 20:54:50 +00:00
Robert Martin
66b456d3c6 C#: Fix a URL redirection from remote source false positive
When guarding the redirect with `HttpRequestBase.IsUrlLocalToHost()`
2023-11-29 13:46:47 -07:00
Jami Cogswell
d5fd2db1bd Java update UrlPathHelper tests 2023-11-29 15:23:11 -05:00
Jami Cogswell
ba3548b317 Java: switch to createRelative sink and add UrlPathHelper sources 2023-11-29 14:46:28 -05:00
Jami Cogswell
efa5ab18c1 Java: add taint steps for getResource sink 2023-11-29 14:46:27 -05:00
Mathias Vorreiter Pedersen
911f1543e0 DataFlow: Adjust QLDoc. 2023-11-28 15:26:48 +00:00
Mathias Vorreiter Pedersen
339bf1363a DataFlow: s/flowThroughStepAllowed/validParameterAliasStep. 2023-11-28 14:32:23 +00:00
Mathias Vorreiter Pedersen
e47ad274ea C++: Add Schack's tests. 2023-11-28 14:32:21 +00:00
Mathias Vorreiter Pedersen
fb6329fbc1 C++: Fix test annotation 2023-11-28 14:27:15 +00:00
Mathias Vorreiter Pedersen
1771d77c23 C++: Accept test changes. 2023-11-28 14:27:15 +00:00
Mathias Vorreiter Pedersen
9049932f42 C++: Implement the new predicate. 2023-11-28 14:27:15 +00:00
Mathias Vorreiter Pedersen
064f68fdca DataFlow: Add a predicate for modifying which dataflow steps participate in flow-through summaries. 2023-11-28 14:27:15 +00:00
Mathias Vorreiter Pedersen
1753a7e146 C++: Add tests. 2023-11-28 14:27:15 +00:00
Owen Mansel-Chan
de87dd5dee Test no result if deferred function returns error 2023-11-28 14:23:37 +00:00
Owen Mansel-Chan
57dafd3732 Improve test for UnhandledCloseWritableHandle
Now the different paths won't have the same two sources.
2023-11-28 14:21:43 +00:00
Alex Eyers-Taylor
3e9aeac004 CPP: Fix sscanf false positives in older linux repos 2023-11-28 12:07:05 +00:00
Geoffrey White
68a9154106 Swift: Merge the two PrintfFormat implementations. 2023-11-28 12:03:05 +00:00
Geoffrey White
5f4213004b Merge branch 'main' into logsinks 2023-11-28 11:51:56 +00:00
Geoffrey White
09998a9f35 Swift: Formatting. 2023-11-27 19:53:32 +00:00
Geoffrey White
f1f5745ed1 Swift: Change note. 2023-11-27 19:43:15 +00:00
Geoffrey White
f19c6f337d Swift: Add imprecise append/insert models. 2023-11-27 19:43:15 +00:00
Geoffrey White
6e5c285346 Swift: Add imprecise init(data:) model. 2023-11-27 19:23:40 +00:00
Geoffrey White
99aa754b50 Swift: Add tests for UIImage. 2023-11-27 19:19:12 +00:00
Geoffrey White
da648b1014 Swift: Convert ui.swift test to use source labels. 2023-11-27 19:06:52 +00:00
Geoffrey White
4b87dd54fb Swift: Add tests for custom append/insert. 2023-11-27 19:02:45 +00:00
Alex Eyers-Taylor
9eb5b23f54 CPP: Fix query formatting 2023-11-27 15:55:44 +00:00
Harry Maclean
bd575db254 Ruby: Add test for FrameworkModeEndpoints query 2023-11-27 14:18:18 +00:00
Harry Maclean
f40f2db3ab Ruby: Fix name of url-redirection sink model 2023-11-27 11:25:37 +00:00
Harry Maclean
6a38223127 Ruby: QL4QL fix 2023-11-27 10:17:31 +00:00
Harry Maclean
e9277a56a9 Ruby: Add sinks from external models 2023-11-27 09:18:00 +00:00
Harry Maclean
ad608341ab Ruby: Handle alternative gemspec names
Gemspecs are sometimes named via the first argument to
`Gem::Specification.new`:

```rb
Gem::Specification.new 'sinatra' do |s|
  # ...
end
```
2023-11-27 09:18:00 +00:00
Harry Maclean
9b998a39b4 Ruby: Add tags to GenerateModel query
This allows the model editor to find this query in a more robust way
than by file path.
2023-11-27 09:18:00 +00:00
Harry Maclean
b9d15bacba Ruby: Don't classify our test files as test files
For model editing purposes.
2023-11-27 09:17:59 +00:00
Harry Maclean
064b10a5cb Ruby: Handle missing gemspec in model query 2023-11-27 09:17:59 +00:00
Harry Maclean
9dcc424f8c Ruby: Include keyword parameters endpoint query 2023-11-27 09:17:59 +00:00
Harry Maclean
5dcc3d43ca Ruby: Recognise modeled source/sink methods 2023-11-27 09:17:59 +00:00
Harry Maclean
766e68aa36 Ruby: Handle multiple gemspecs in endpoints query 2023-11-27 09:17:59 +00:00
Harry Maclean
c54743c3fd Ruby: Include class methods in model editor query 2023-11-27 09:17:59 +00:00
Harry Maclean
78125a701d Ruby: Model Editor support
Add experimental support for the CodeQL Model Editor.
2023-11-27 09:17:59 +00:00
Geoffrey White
4c2a6231e9 Swift: Add tests for array append/insert. 2023-11-24 18:33:25 +00:00
Jeroen Ketema
c02a732632 C++: Remove DefaultTaintTracking library 2023-11-24 18:35:19 +01:00
Alex Eyers-Taylor
1c012548d4 CPP: Add tests for incorrect check scanf 2023-11-24 16:58:11 +00:00
Alex Eyers-Taylor
12e24a2b44 CPP: Exclude incorrect scanf checks from missing scanf checks 2023-11-24 16:57:59 +00:00
Alex Eyers-Taylor
f48e8b6062 CPP: Add query for detecteing incorrect error checking for scanf 2023-11-24 14:53:10 +00:00
yoff
4785048076 Apply suggestions from code review
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
2023-11-22 09:29:07 +01:00
Mathias Vorreiter Pedersen
a80dbc5200 C++: Accept test changes. 2023-11-21 17:50:11 +00:00
Mathias Vorreiter Pedersen
976adc3c7c C++: Fixup queries to keep the old results. 2023-11-21 17:50:08 +00:00
Mathias Vorreiter Pedersen
ef2caa3944 C++: Add a new API for mapping a dataflow node to a definition. This means we can reduce duplication from 'asExpr'. 2023-11-21 17:49:02 +00:00
Geoffrey White
c89be6a1de Swift: Refine the heuristic (mostly narrower). 2023-11-21 13:49:53 +00:00
Geoffrey White
5bbc61e83c Swift: Add a few more test cases. 2023-11-21 11:32:40 +00:00
Tom Hvitved
12359ba733 Add change note 2023-11-21 11:46:15 +01:00
Geoffrey White
57a1becd22 Swift: Add missing QLDoc. 2023-11-21 08:55:52 +00:00
Rasmus Lerchedahl Petersen
c8b87f71c5 Python: add change note 2023-11-20 21:44:16 +01:00
Rasmus Lerchedahl Petersen
421d4f3497 Python: filter more sinks in stdlib
Rename variable to reflect larger scope

We had test results inside `os.py`, I suppose we have found a little extra flow.
2023-11-20 21:35:52 +01:00
Rasmus Lerchedahl Petersen
11c71fdd18 Python: remove EssaNodes
This commit removes SSA nodes from the data flow graph. Specifically, for a definition and use such as
```python
  x = expr
  y = x + 2
```
we used to have flow from `expr` to an SSA variable representing x and from that SSA variable to the use of `x` in the definition of `y`. Now we instead have flow from `expr` to the control flow node for `x` at line 1 and from there to the control flow node for `x` at line 2.

Specific changes:
- `EssaNode` from the data flow layer no longer exists.
- Several glue steps between `EssaNode`s and `CfgNode`s have been deleted.
- Entry nodes are now admitted as `CfgNodes` in the data flow layer (they were filtered out before).
- Entry nodes now have a new `toString` taking into account that the module name may be ambigous.
- Some tests have been rewritten to accomodate the changes, but only `python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll` should have semantic changes.
- Comments have been updated
- Test output has been updated, but apart from `python/ql/test/experimental/dataflow/basic/maximalFlows.expected` only `python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py` should have a semantic change. This is a bonus fix, probably meaning that something was never connected up correctly.
2023-11-20 21:35:32 +01:00
Geoffrey White
b4b78a1bce Swift: Minor corrections. 2023-11-20 19:29:35 +00:00
Geoffrey White
50120f65a3 Swift: Change note. 2023-11-20 18:43:48 +00:00
Geoffrey White
3cecf69818 Swift: Fix spurious results for 'login' functions. 2023-11-20 18:38:47 +00:00
Geoffrey White
aa93165d24 Swift: Add heuristic sinks. 2023-11-20 18:38:47 +00:00
Geoffrey White
d91c5c0486 Swift: Model NSException sinks. 2023-11-20 18:38:46 +00:00
Geoffrey White
7e02c05164 Swift: Address the sprintf case. 2023-11-20 18:38:46 +00:00
Geoffrey White
835967a33e Swift: Fix for autoclosure sinks. 2023-11-20 18:15:16 +00:00
Geoffrey White
795f16ba56 Swift: Model 'printf' variants as cleartext logging sinks. 2023-11-20 18:15:06 +00:00
Geoffrey White
06c2c423b3 Swift: Clean up the test logic slightly. 2023-11-20 18:12:15 +00:00
Geoffrey White
b348dc2a32 Swift: Extend cleartext logging tests (test cases). 2023-11-20 18:11:52 +00:00
Geoffrey White
2a69b03092 Swift: Extend cleartext logging tests (stubs). 2023-11-20 18:11:41 +00:00
Tom Hvitved
6ce8e0510f Ruby: Adopt shared type tracking library 2023-11-20 16:03:24 +01:00
Geoffrey White
b926090f0d Swift: Simplify AdoptsWkNavigationDelegate in WebView.qll. 2023-11-06 12:29:32 +00:00
Tony Torralba
107a05af71 Update MaD Declarations after Triage 2023-10-31 16:52:02 +01:00
Tony Torralba
9f7a8aa18c Update MaD Declarations after Triage 2023-10-24 17:42:03 +02:00
Geoffrey White
06c19fd8cf Swift: Add CommonCrypto test cases for the broken crypto query. 2023-08-02 18:36:05 +01:00
1396 changed files with 96905 additions and 58219 deletions

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'

View File

@@ -28,9 +28,9 @@ jobs:
steps:
- name: Setup dotnet
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: 7.0.102
dotnet-version: 8.0.100
- name: Checkout repository
uses: actions/checkout@v4

View File

@@ -72,15 +72,15 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: 7.0.102
dotnet-version: 8.0.100
- name: Extractor unit tests
run: |
dotnet test -p:RuntimeFrameworkVersion=7.0.2 extractor/Semmle.Util.Tests
dotnet test -p:RuntimeFrameworkVersion=7.0.2 extractor/Semmle.Extraction.Tests
dotnet test -p:RuntimeFrameworkVersion=7.0.2 autobuilder/Semmle.Autobuild.CSharp.Tests
dotnet test -p:RuntimeFrameworkVersion=7.0.2 "${{ github.workspace }}/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests"
dotnet test -p:RuntimeFrameworkVersion=8.0.0 extractor/Semmle.Util.Tests
dotnet test -p:RuntimeFrameworkVersion=8.0.0 extractor/Semmle.Extraction.Tests
dotnet test -p:RuntimeFrameworkVersion=8.0.0 autobuilder/Semmle.Autobuild.CSharp.Tests
dotnet test -p:RuntimeFrameworkVersion=8.0.0 "${{ github.workspace }}/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests"
shell: bash
stubgentest:
runs-on: ubuntu-latest

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: macos-latest
steps:
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
id: go
@@ -50,7 +50,7 @@ jobs:
runs-on: windows-latest-xl
steps:
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
id: go

View File

@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest-xl
steps:
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
id: go

View File

@@ -44,3 +44,4 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
# Misc
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
/misc/scripts/generate-code-scanning-query-list.py @RasmusWL

View File

@@ -53,14 +53,6 @@
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
],
"DataFlow Java/C#/Go/Ruby/Python/Swift Flow Summaries": [
"java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll",
"go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll"
],
"SsaReadPosition Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
@@ -462,23 +454,6 @@
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
],
"TypeTracker": [
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
],
"SummaryTypeTracker": [
"python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
"ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll"
],
"AccessPathSyntax": [
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll",
"go/ql/lib/semmle/go/dataflow/internal/AccessPathSyntax.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/AccessPathSyntax.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/AccessPathSyntax.qll"
],
"IncompleteUrlSubstringSanitization": [
"javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll",
"ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll"
@@ -534,4 +509,4 @@
"python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml",
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
]
}
}

View File

@@ -326,7 +326,7 @@ namespace Semmle.Autobuild.Cpp.Tests
public void TestCppAutobuilderSuccess()
{
Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1;
Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
Actions.RunProcess[@"cmd.exe /C scratch\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program^ Files^ ^(x86^)\Microsoft^ Visual^ Studio^ 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"""] = 0;
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
@@ -337,10 +337,11 @@ namespace Semmle.Autobuild.Cpp.Tests
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true;
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true;
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true;
Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CPP_SCRATCH_DIR"] = "scratch";
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx";
Actions.EnumerateDirectories[@"C:\Project"] = "";
Actions.CreateDirectories.Add(@"C:\Project\.nuget");
Actions.DownloadFiles.Add(("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", @"C:\Project\.nuget\nuget.exe"));
Actions.CreateDirectories.Add(@"scratch\.nuget");
Actions.DownloadFiles.Add(("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", @"scratch\.nuget\nuget.exe"));
var autobuilder = CreateAutoBuilder(true);
var solution = new TestSolution(@"C:\Project\test.sln");

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
@@ -11,12 +11,12 @@
<ItemGroup>
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PackageReference Include="xunit" Version="2.6.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>Semmle.Autobuild.Cpp</AssemblyName>
<RootNamespace>Semmle.Autobuild.Cpp</RootNamespace>
<ApplicationIcon />
@@ -17,7 +17,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="17.3.2" />
<PackageReference Include="Microsoft.Build" Version="17.8.3" />
</ItemGroup>
<ItemGroup>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Revert removal of uniqueness constraint on link_targets/2
compatibility: backwards

View File

@@ -52,17 +52,18 @@ class Options extends string {
/**
* Holds if a call to this function will never return.
*
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
* `longjmp`, `__builtin_unreachable` and any function with a
* `noreturn` attribute or specifier.
* By default, this holds for `exit`, `_exit`, `_Exit`, `abort`,
* `__assert_fail`, `longjmp`, `__builtin_unreachable` and any
* function with a `noreturn` or `__noreturn__` attribute or
* `noreturn` specifier.
*/
predicate exits(Function f) {
f.getAnAttribute().hasName("noreturn")
f.getAnAttribute().hasName(["noreturn", "__noreturn__"])
or
f.getASpecifier().hasName("noreturn")
or
f.hasGlobalOrStdName([
"exit", "_exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
"exit", "_exit", "_Exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
])
or
CustomOptions::exits(f) // old Options.qll

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `Guards` library has been replaced with the API-compatible `IRGuards` implementation, which has better precision in some cases.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The deprecated `DefaultTaintTracking` library has been removed.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added a new predicate `Node.asDefinition` on `DataFlow::Node`s for selecting the dataflow node corresponding to a particular definition.

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `isUserInput`, `userInputArgument`, and `userInputReturned` predicates from `SecurityOptions` have been deprecated. Use `FlowSource` instead.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Changed the output of `Node.toString` to better reflect how many indirections a given dataflow node has.

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.12.1
version: 0.12.2-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -328,6 +328,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
MetricFunction getMetrics() { result = this }
/** Holds if this function calls the function `f`. */
pragma[nomagic]
predicate calls(Function f) { this.calls(f, _) }
/**
@@ -338,10 +339,6 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
exists(FunctionCall call |
call.getEnclosingFunction() = this and call.getTarget() = f and call = l
)
or
exists(DestructorCall call |
call.getEnclosingFunction() = this and call.getTarget() = f and call = l
)
}
/** Holds if this function accesses a function or variable or enumerator `a`. */

View File

@@ -7,371 +7,7 @@ import cpp
import semmle.code.cpp.controlflow.BasicBlocks
import semmle.code.cpp.controlflow.SSA
import semmle.code.cpp.controlflow.Dominance
/**
* A Boolean condition that guards one or more basic blocks. This includes
* operands of logical operators but not switch statements.
*/
class GuardCondition extends Expr {
GuardCondition() { is_condition(this) }
/**
* Holds if this condition controls `block`, meaning that `block` is only
* entered if the value of this condition is `testIsTrue`.
*
* Illustration:
*
* ```
* [ (testIsTrue) ]
* [ this ----------------succ ---- controlled ]
* [ | | ]
* [ (testIsFalse) | ------ ... ]
* [ other ]
* ```
*
* The predicate holds if all paths to `controlled` go via the `testIsTrue`
* edge of the control-flow graph. In other words, the `testIsTrue` edge
* must dominate `controlled`. This means that `controlled` must be
* dominated by both `this` and `succ` (the target of the `testIsTrue`
* edge). It also means that any other edge into `succ` must be a back-edge
* from a node which is dominated by `succ`.
*
* The short-circuit boolean operations have slightly surprising behavior
* here: because the operation itself only dominates one branch (due to
* being short-circuited) then it will only control blocks dominated by the
* true (for `&&`) or false (for `||`) branch.
*/
cached
predicate controls(BasicBlock controlled, boolean testIsTrue) {
// This condition must determine the flow of control; that is, this
// node must be a top-level condition.
this.controlsBlock(controlled, testIsTrue)
or
exists(BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs |
this = binop and
lhs = binop.getLeftOperand() and
rhs = binop.getRightOperand() and
lhs.controls(controlled, testIsTrue) and
rhs.controls(controlled, testIsTrue)
)
or
exists(GuardCondition ne, GuardCondition operand |
this = operand and
operand = ne.(NotExpr).getOperand() and
ne.controls(controlled, testIsTrue.booleanNot())
)
}
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
cached
predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
compares_lt(this, left, right, k, isLessThan, testIsTrue)
}
/**
* Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
* If `isLessThan = false` then this implies `left >= right + k`.
*/
cached
predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
exists(boolean testIsTrue |
compares_lt(this, left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
)
}
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
cached
predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
compares_eq(this, left, right, k, areEqual, testIsTrue)
}
/**
* Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
* If `areEqual = false` then this implies `left != right + k`.
*/
cached
predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
exists(boolean testIsTrue |
compares_eq(this, left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue)
)
}
/**
* Holds if this condition controls `block`, meaning that `block` is only
* entered if the value of this condition is `testIsTrue`. This helper
* predicate does not necessarily hold for binary logical operations like
* `&&` and `||`. See the detailed explanation on predicate `controls`.
*/
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
exists(BasicBlock thisblock | thisblock.contains(this) |
exists(BasicBlock succ |
testIsTrue = true and succ = this.getATrueSuccessor()
or
testIsTrue = false and succ = this.getAFalseSuccessor()
|
bbDominates(succ, controlled) and
forall(BasicBlock pred | pred.getASuccessor() = succ |
pred = thisblock or bbDominates(succ, pred) or not reachable(pred)
)
)
)
}
}
private predicate is_condition(Expr guard) {
guard.isCondition()
or
is_condition(guard.(BinaryLogicalOperation).getAnOperand())
or
exists(NotExpr cond | is_condition(cond) and cond.getOperand() = guard)
}
/*
* Simplification of equality expressions:
* Simplify conditions in the source to the canonical form l op r + k.
*/
/**
* Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`.
*
* Beware making mistaken logical implications here relating `areEqual` and `testIsTrue`.
*/
private predicate compares_eq(
Expr test, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
exists(boolean eq | simple_comparison_eq(test, left, right, k, eq) |
areEqual = true and testIsTrue = eq
or
areEqual = false and testIsTrue = eq.booleanNot()
)
or
logical_comparison_eq(test, left, right, k, areEqual, testIsTrue)
or
/* a == b + k => b == a - k */
exists(int mk | k = -mk | compares_eq(test, right, left, mk, areEqual, testIsTrue))
or
complex_eq(test, left, right, k, areEqual, testIsTrue)
or
/* (x is true => (left == right + k)) => (!x is false => (left == right + k)) */
exists(boolean isFalse | testIsTrue = isFalse.booleanNot() |
compares_eq(test.(NotExpr).getOperand(), left, right, k, areEqual, isFalse)
)
}
/**
* If `test => part` and `part => left == right + k` then `test => left == right + k`.
* Similarly for the case where `test` is false.
*/
private predicate logical_comparison_eq(
BinaryLogicalOperation test, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
exists(boolean partIsTrue, Expr part | test.impliesValue(part, partIsTrue, testIsTrue) |
compares_eq(part, left, right, k, areEqual, partIsTrue)
)
}
/** Rearrange various simple comparisons into `left == right + k` form. */
private predicate simple_comparison_eq(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean areEqual
) {
left = cmp.getLeftOperand() and
cmp.getOperator() = "==" and
right = cmp.getRightOperand() and
k = 0 and
areEqual = true
or
left = cmp.getLeftOperand() and
cmp.getOperator() = "!=" and
right = cmp.getRightOperand() and
k = 0 and
areEqual = false
}
private predicate complex_eq(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
sub_eq(cmp, left, right, k, areEqual, testIsTrue)
or
add_eq(cmp, left, right, k, areEqual, testIsTrue)
}
// left - x == right + c => left == right + (c+x)
// left == (right - x) + c => left == right + (c-x)
private predicate sub_eq(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
exists(SubExpr lhs, int c, int x |
compares_eq(cmp, lhs, right, c, areEqual, testIsTrue) and
left = lhs.getLeftOperand() and
x = int_value(lhs.getRightOperand()) and
k = c + x
)
or
exists(SubExpr rhs, int c, int x |
compares_eq(cmp, left, rhs, c, areEqual, testIsTrue) and
right = rhs.getLeftOperand() and
x = int_value(rhs.getRightOperand()) and
k = c - x
)
}
// left + x == right + c => left == right + (c-x)
// left == (right + x) + c => left == right + (c+x)
private predicate add_eq(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
exists(AddExpr lhs, int c, int x |
compares_eq(cmp, lhs, right, c, areEqual, testIsTrue) and
(
left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
or
left = lhs.getRightOperand() and x = int_value(lhs.getLeftOperand())
) and
k = c - x
)
or
exists(AddExpr rhs, int c, int x |
compares_eq(cmp, left, rhs, c, areEqual, testIsTrue) and
(
right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
or
right = rhs.getRightOperand() and x = int_value(rhs.getLeftOperand())
) and
k = c + x
)
}
/*
* Simplification of inequality expressions:
* Simplify conditions in the source to the canonical form l < r + k.
*/
/** Holds if `left < right + k` evaluates to `isLt` given that test is `testIsTrue`. */
private predicate compares_lt(
Expr test, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
/* In the simple case, the test is the comparison, so isLt = testIsTrue */
simple_comparison_lt(test, left, right, k) and isLt = true and testIsTrue = true
or
simple_comparison_lt(test, left, right, k) and isLt = false and testIsTrue = false
or
logical_comparison_lt(test, left, right, k, isLt, testIsTrue)
or
complex_lt(test, left, right, k, isLt, testIsTrue)
or
/* (not (left < right + k)) => (left >= right + k) */
exists(boolean isGe | isLt = isGe.booleanNot() |
compares_ge(test, left, right, k, isGe, testIsTrue)
)
or
/* (x is true => (left < right + k)) => (!x is false => (left < right + k)) */
exists(boolean isFalse | testIsTrue = isFalse.booleanNot() |
compares_lt(test.(NotExpr).getOperand(), left, right, k, isLt, isFalse)
)
}
/** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */
private predicate compares_ge(
Expr test, Expr left, Expr right, int k, boolean isGe, boolean testIsTrue
) {
exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, testIsTrue))
}
/**
* If `test => part` and `part => left < right + k` then `test => left < right + k`.
* Similarly for the case where `test` evaluates false.
*/
private predicate logical_comparison_lt(
BinaryLogicalOperation test, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
exists(boolean partIsTrue, Expr part | test.impliesValue(part, partIsTrue, testIsTrue) |
compares_lt(part, left, right, k, isLt, partIsTrue)
)
}
/** Rearrange various simple comparisons into `left < right + k` form. */
private predicate simple_comparison_lt(ComparisonOperation cmp, Expr left, Expr right, int k) {
left = cmp.getLeftOperand() and
cmp.getOperator() = "<" and
right = cmp.getRightOperand() and
k = 0
or
left = cmp.getLeftOperand() and
cmp.getOperator() = "<=" and
right = cmp.getRightOperand() and
k = 1
or
right = cmp.getLeftOperand() and
cmp.getOperator() = ">" and
left = cmp.getRightOperand() and
k = 0
or
right = cmp.getLeftOperand() and
cmp.getOperator() = ">=" and
left = cmp.getRightOperand() and
k = 1
}
private predicate complex_lt(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
sub_lt(cmp, left, right, k, isLt, testIsTrue)
or
add_lt(cmp, left, right, k, isLt, testIsTrue)
}
// left - x < right + c => left < right + (c+x)
// left < (right - x) + c => left < right + (c-x)
private predicate sub_lt(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
exists(SubExpr lhs, int c, int x |
compares_lt(cmp, lhs, right, c, isLt, testIsTrue) and
left = lhs.getLeftOperand() and
x = int_value(lhs.getRightOperand()) and
k = c + x
)
or
exists(SubExpr rhs, int c, int x |
compares_lt(cmp, left, rhs, c, isLt, testIsTrue) and
right = rhs.getLeftOperand() and
x = int_value(rhs.getRightOperand()) and
k = c - x
)
}
// left + x < right + c => left < right + (c-x)
// left < (right + x) + c => left < right + (c+x)
private predicate add_lt(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
exists(AddExpr lhs, int c, int x |
compares_lt(cmp, lhs, right, c, isLt, testIsTrue) and
(
left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
or
left = lhs.getRightOperand() and x = int_value(lhs.getLeftOperand())
) and
k = c - x
)
or
exists(AddExpr rhs, int c, int x |
compares_lt(cmp, left, rhs, c, isLt, testIsTrue) and
(
right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
or
right = rhs.getRightOperand() and x = int_value(rhs.getLeftOperand())
) and
k = c + x
)
}
/** The `int` value of integer constant expression. */
private int int_value(Expr e) {
e.getUnderlyingType() instanceof IntegralType and
result = e.getValue().toInt()
}
import IRGuards
/** An `SsaDefinition` with an additional predicate `isLt`. */
class GuardedSsa extends SsaDefinition {

View File

@@ -5,6 +5,8 @@
import cpp
import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
/**
* Holds if `block` consists of an `UnreachedInstruction`.
@@ -201,12 +203,30 @@ private class GuardConditionFromIR extends GuardCondition {
* `&&` and `||`. See the detailed explanation on predicate `controls`.
*/
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
exists(IRBlock irb |
exists(IRBlock irb, Instruction instr |
ir.controls(irb, testIsTrue) and
irb.getAnInstruction().getAst().(ControlFlowNode).getBasicBlock() = controlled and
not isUnreachedBlock(irb)
instr = irb.getAnInstruction() and
instr.getAst().(ControlFlowNode).getBasicBlock() = controlled and
not isUnreachedBlock(irb) and
not this.excludeAsControlledInstruction(instr)
)
}
private predicate excludeAsControlledInstruction(Instruction instr) {
// Exclude the temporaries generated by a ternary expression.
exists(TranslatedConditionalExpr tce |
instr = tce.getInstruction(ConditionValueFalseStoreTag())
or
instr = tce.getInstruction(ConditionValueTrueStoreTag())
or
instr = tce.getInstruction(ConditionValueTrueTempAddressTag())
or
instr = tce.getInstruction(ConditionValueFalseTempAddressTag())
)
or
// Exclude unreached instructions, as their AST is the whole function and not a block.
instr instanceof UnreachedInstruction
}
}
/**

View File

@@ -10,10 +10,12 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
deprecated import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -48,7 +50,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -189,7 +191,7 @@ abstract class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -210,7 +212,7 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
private FlowState relevantState(Configuration config) {
deprecated private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -219,17 +221,17 @@ private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
deprecated TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
deprecated private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -296,13 +298,13 @@ private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
deprecated private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
deprecated class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -329,10 +331,10 @@ class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
deprecated final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -347,9 +349,9 @@ class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
module PathGraph = I::PathGraph;
deprecated module PathGraph = I::PathGraph;
private predicate hasFlow(Node source, Node sink, Configuration config) {
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -357,10 +359,10 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;
deprecated predicate flowsTo = hasFlow/3;

View File

@@ -10,10 +10,12 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
deprecated import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -48,7 +50,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -189,7 +191,7 @@ abstract class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -210,7 +212,7 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
private FlowState relevantState(Configuration config) {
deprecated private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -219,17 +221,17 @@ private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
deprecated TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
deprecated private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -296,13 +298,13 @@ private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
deprecated private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
deprecated class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -329,10 +331,10 @@ class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
deprecated final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -347,9 +349,9 @@ class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
module PathGraph = I::PathGraph;
deprecated module PathGraph = I::PathGraph;
private predicate hasFlow(Node source, Node sink, Configuration config) {
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -357,10 +359,10 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;
deprecated predicate flowsTo = hasFlow/3;

View File

@@ -10,10 +10,12 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
deprecated import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -48,7 +50,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -189,7 +191,7 @@ abstract class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -210,7 +212,7 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
private FlowState relevantState(Configuration config) {
deprecated private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -219,17 +221,17 @@ private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
deprecated TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
deprecated private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -296,13 +298,13 @@ private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
deprecated private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
deprecated class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -329,10 +331,10 @@ class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
deprecated final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -347,9 +349,9 @@ class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
module PathGraph = I::PathGraph;
deprecated module PathGraph = I::PathGraph;
private predicate hasFlow(Node source, Node sink, Configuration config) {
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -357,10 +359,10 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;
deprecated predicate flowsTo = hasFlow/3;

View File

@@ -10,10 +10,12 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
deprecated import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -48,7 +50,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -189,7 +191,7 @@ abstract class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -210,7 +212,7 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
private FlowState relevantState(Configuration config) {
deprecated private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -219,17 +221,17 @@ private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
deprecated TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
deprecated private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -296,13 +298,13 @@ private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
deprecated private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
deprecated class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -329,10 +331,10 @@ class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
deprecated final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -347,9 +349,9 @@ class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
module PathGraph = I::PathGraph;
deprecated module PathGraph = I::PathGraph;
private predicate hasFlow(Node source, Node sink, Configuration config) {
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -357,10 +359,10 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;
deprecated predicate flowsTo = hasFlow/3;

View File

@@ -10,10 +10,12 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
deprecated import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -48,7 +50,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -189,7 +191,7 @@ abstract class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -210,7 +212,7 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
private FlowState relevantState(Configuration config) {
deprecated private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -219,17 +221,17 @@ private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
deprecated TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
deprecated private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -296,13 +298,13 @@ private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
deprecated private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
deprecated class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -329,10 +331,10 @@ class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
deprecated final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -347,9 +349,9 @@ class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
module PathGraph = I::PathGraph;
deprecated module PathGraph = I::PathGraph;
private predicate hasFlow(Node source, Node sink, Configuration config) {
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -357,10 +359,10 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;
deprecated predicate flowsTo = hasFlow/3;

View File

@@ -1,4 +1,6 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -12,6 +14,8 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -51,7 +55,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract class Configuration extends DataFlow::Configuration {
abstract deprecated class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -1,4 +1,6 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -12,6 +14,8 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -51,7 +55,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract class Configuration extends DataFlow::Configuration {
abstract deprecated class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -1,21 +0,0 @@
/**
* DEPRECATED: Use `semmle.code.cpp.ir.dataflow.TaintTracking` as a replacement.
*
* An IR taint tracking library that uses an IR DataFlow configuration to track
* taint from user inputs as defined by `semmle.code.cpp.security.Security`.
*/
import cpp
import semmle.code.cpp.security.Security
private import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl as DefaultTaintTrackingImpl
deprecated predicate predictableOnlyFlow = DefaultTaintTrackingImpl::predictableOnlyFlow/1;
deprecated predicate tainted = DefaultTaintTrackingImpl::tainted/2;
deprecated predicate taintedIncludingGlobalVars =
DefaultTaintTrackingImpl::taintedIncludingGlobalVars/3;
deprecated predicate globalVarFromId = DefaultTaintTrackingImpl::globalVarFromId/1;
deprecated module TaintedWithPath = DefaultTaintTrackingImpl::TaintedWithPath;

View File

@@ -10,10 +10,12 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
deprecated import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -48,7 +50,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -189,7 +191,7 @@ abstract class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -210,7 +212,7 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
private FlowState relevantState(Configuration config) {
deprecated private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -219,17 +221,17 @@ private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
deprecated TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
deprecated private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -296,13 +298,13 @@ private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
deprecated private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
deprecated class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -329,10 +331,10 @@ class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
deprecated final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -347,9 +349,9 @@ class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
module PathGraph = I::PathGraph;
deprecated module PathGraph = I::PathGraph;
private predicate hasFlow(Node source, Node sink, Configuration config) {
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -357,10 +359,10 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;
deprecated predicate flowsTo = hasFlow/3;

View File

@@ -10,10 +10,12 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
deprecated import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -48,7 +50,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -189,7 +191,7 @@ abstract class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -210,7 +212,7 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
private FlowState relevantState(Configuration config) {
deprecated private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -219,17 +221,17 @@ private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
deprecated TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
deprecated private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -296,13 +298,13 @@ private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
deprecated private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
deprecated class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -329,10 +331,10 @@ class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
deprecated final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -347,9 +349,9 @@ class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
module PathGraph = I::PathGraph;
deprecated module PathGraph = I::PathGraph;
private predicate hasFlow(Node source, Node sink, Configuration config) {
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -357,10 +359,10 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;
deprecated predicate flowsTo = hasFlow/3;

View File

@@ -10,10 +10,12 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
deprecated import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -48,7 +50,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -189,7 +191,7 @@ abstract class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -210,7 +212,7 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
private FlowState relevantState(Configuration config) {
deprecated private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -219,17 +221,17 @@ private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
deprecated TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
deprecated private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -296,13 +298,13 @@ private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
deprecated private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
deprecated class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -329,10 +331,10 @@ class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
deprecated final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -347,9 +349,9 @@ class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
module PathGraph = I::PathGraph;
deprecated module PathGraph = I::PathGraph;
private predicate hasFlow(Node source, Node sink, Configuration config) {
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -357,10 +359,10 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;
deprecated predicate flowsTo = hasFlow/3;

View File

@@ -10,10 +10,12 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
import FlowStateString
deprecated import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -48,7 +50,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -189,7 +191,7 @@ abstract class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract private class ConfigurationRecursionPrevention extends Configuration {
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -210,7 +212,7 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
}
}
private FlowState relevantState(Configuration config) {
deprecated private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -219,17 +221,17 @@ private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
TMkConfigState(Configuration config, FlowState state) {
deprecated TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private module Config implements FullStateConfigSig {
deprecated private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -296,13 +298,13 @@ private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
private import Impl<Config> as I
deprecated private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof I::PathNode {
deprecated class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -329,10 +331,10 @@ class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = getState(super.getState()) }
deprecated final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = getConfig(super.getState()) }
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -347,9 +349,9 @@ class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
module PathGraph = I::PathGraph;
deprecated module PathGraph = I::PathGraph;
private predicate hasFlow(Node source, Node sink, Configuration config) {
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -357,10 +359,10 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
)
}
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
predicate flowsTo = hasFlow/3;
deprecated predicate flowsTo = hasFlow/3;

View File

@@ -20,4 +20,6 @@ module CppDataFlow implements InputSig {
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
predicate getAdditionalFlowIntoCallNodeTerm = Private::getAdditionalFlowIntoCallNodeTerm/2;
predicate validParameterAliasStep = Private::validParameterAliasStep/2;
}

View File

@@ -6,6 +6,7 @@ private import semmle.code.cpp.ir.internal.IRCppLanguage
private import SsaInternals as Ssa
private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
private import Node0ToString
cached
private module Cached {
@@ -58,6 +59,41 @@ private module Cached {
import Cached
private import Nodes0
/**
* A module for calculating the number of stars (i.e., `*`s) needed for various
* dataflow node `toString` predicates.
*/
module NodeStars {
private int getNumberOfIndirections(Node n) {
result = n.(RawIndirectOperand).getIndirectionIndex()
or
result = n.(RawIndirectInstruction).getIndirectionIndex()
or
result = n.(VariableNode).getIndirectionIndex()
or
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
or
result = n.(FinalParameterNode).getIndirectionIndex()
}
private int maxNumberOfIndirections() { result = max(getNumberOfIndirections(_)) }
private string repeatStars(int n) {
n = 0 and result = ""
or
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
/**
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
* output for `n`.
*/
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
}
import NodeStars
class Node0Impl extends TIRDataFlowNode0 {
/**
* INTERNAL: Do not use.
@@ -138,11 +174,7 @@ abstract class InstructionNode0 extends Node0Impl {
override DataFlowType getType() { result = getInstructionType(instr, _) }
override string toStringImpl() {
if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = instr.getAst().toString()
}
override string toStringImpl() { result = instructionToString(instr) }
override Location getLocationImpl() {
if exists(instr.getAst().getLocation())
@@ -187,11 +219,7 @@ abstract class OperandNode0 extends Node0Impl {
override DataFlowType getType() { result = getOperandType(op, _) }
override string toStringImpl() {
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
override string toStringImpl() { result = operandToString(op) }
override Location getLocationImpl() {
if exists(op.getDef().getAst().getLocation())
@@ -1149,3 +1177,55 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
)
)
}
/**
* Holds if the data-flow step from `node1` to `node2` can be used to
* determine where side-effects may return from a callable.
* For C/C++, this means that the step from `node1` to `node2` not only
* preserves the value, but also preserves the identity of the value.
* For example, the assignment to `x` that reads the value of `*p` in
* ```cpp
* int* p = ...
* int x = *p;
* ```
* does not preserve the identity of `*p`.
*/
bindingset[node1, node2]
pragma[inline_late]
predicate validParameterAliasStep(Node node1, Node node2) {
// When flow-through summaries are computed we track which parameters flow to out-going parameters.
// In an example such as:
// ```
// modify(int* px) { *px = source(); }
// void modify_copy(int* p) {
// int x = *p;
// modify(&x);
// }
// ```
// since dataflow tracks each indirection as a separate SSA variable dataflow
// sees the above roughly as
// ```
// modify(int* px, int deref_px) { deref_px = source(); }
// void modify_copy(int* p, int deref_p) {
// int x = deref_p;
// modify(&x, x);
// }
// ```
// and when dataflow computes flow from a parameter to a post-update node to
// conclude which parameters are "updated" by the call to `modify_copy` it
// finds flow from `x [post update]` to `deref_p [post update]`.
// To prevent this we exclude steps that don't preserve identity. We do this
// by excluding flow from the right-hand side of `StoreInstruction`s to the
// `StoreInstruction`. This is sufficient because, for flow-through summaries,
// we're only interested in indirect parameters such as `deref_p` in the
// exampe above (i.e., the parameters with a non-zero indirection index), and
// if that ever flows to the right-hand side of a `StoreInstruction` then
// there must have been a dereference to reduce its indirection index down to
// 0.
not exists(Operand operand |
node1.asOperand() = operand and
node2.asInstruction().(StoreInstruction).getSourceValueOperand() = operand
)
// TODO: Also block flow through models that don't preserve identity such
// as `strdup`.
}

View File

@@ -15,20 +15,21 @@ private import ModelUtil
private import SsaInternals as Ssa
private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
private import Node0ToString
/**
* The IR dataflow graph consists of the following nodes:
* - `Node0`, which injects most instructions and operands directly into the dataflow graph.
* - `Node0`, which injects most instructions and operands directly into the
* dataflow graph.
* - `VariableNode`, which is used to model flow through global variables.
* - `PostFieldUpdateNode`, which is used to model the state of a field after a value has been stored
* into an address after a number of loads.
* - `SsaPhiNode`, which represents phi nodes as computed by the shared SSA library.
* - `IndirectArgumentOutNode`, which represents the value of an argument (and its indirections) after
* it leaves a function call.
* - `RawIndirectOperand`, which represents the value of `operand` after loading the address a number
* of times.
* - `RawIndirectInstruction`, which represents the value of `instr` after loading the address a number
* of times.
* - `PostUpdateNodeImpl`, which is used to model the state of an object after
* an update after a number of loads.
* - `SsaPhiNode`, which represents phi nodes as computed by the shared SSA
* library.
* - `RawIndirectOperand`, which represents the value of `operand` after
* loading the address a number of times.
* - `RawIndirectInstruction`, which represents the value of `instr` after
* loading the address a number of times.
*/
cached
private newtype TIRDataFlowNode =
@@ -37,14 +38,13 @@ private newtype TIRDataFlowNode =
indirectionIndex =
[getMinIndirectionsForType(var.getUnspecifiedType()) .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
} or
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
indirectionIndex =
[1 .. Ssa::countIndirectionsForCppType(operand.getObjectAddress().getResultLanguageType())]
} or
TSsaPhiNode(Ssa::PhiNode phi) or
TIndirectArgumentOutNode(ArgumentOperand operand, int indirectionIndex) {
TPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
operand = any(FieldAddress fa).getObjectAddressOperand() and
indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(Ssa::getLanguageType(operand))]
or
Ssa::isModifiableByCall(operand, indirectionIndex)
} or
TSsaPhiNode(Ssa::PhiNode phi) or
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
} or
@@ -84,7 +84,7 @@ private predicate parameterIsRedefined(Parameter p) {
class FieldAddress extends Operand {
FieldAddressInstruction fai;
FieldAddress() { fai = this.getDef() }
FieldAddress() { fai = this.getDef() and not Ssa::ignoreOperand(this) }
/** Gets the field associated with this instruction. */
Field getField() { result = fai.getField() }
@@ -260,6 +260,71 @@ class Node extends TIRDataFlowNode {
*/
Expr asDefiningArgument() { result = this.asDefiningArgument(_) }
/**
* Gets the definition associated with this node, if any.
*
* For example, consider the following example
* ```cpp
* int x = 42; // 1
* x = 34; // 2
* ++x; // 3
* x++; // 4
* x += 1; // 5
* int y = x += 2; // 6
* ```
* - For (1) the result is `42`.
* - For (2) the result is `x = 34`.
* - For (3) the result is `++x`.
* - For (4) the result is `x++`.
* - For (5) the result is `x += 1`.
* - For (6) there are two results:
* - For the definition generated by `x += 2` the result is `x += 2`
* - For the definition generated by `int y = ...` the result is
* also `x += 2`.
*
* For assignments, `node.asDefinition()` and `node.asExpr()` will both exist
* for the same dataflow node. However, for expression such as `x++` that
* both write to `x` and read the current value of `x`, `node.asDefinition()`
* will give the node corresponding to the value after the increment, and
* `node.asExpr()` will give the node corresponding to the value before the
* increment. For an example of this, consider the following:
*
* ```cpp
* sink(x++);
* ```
* in the above program, there will not be flow from a node `n` such that
* `n.asDefinition() instanceof IncrementOperation` to the argument of `sink`
* since the value passed to `sink` is the value before to the increment.
* However, there will be dataflow from a node `n` such that
* `n.asExpr() instanceof IncrementOperation` since the result of evaluating
* the expression `x++` is passed to `sink`.
*/
Expr asDefinition() {
exists(StoreInstruction store |
store = this.asInstruction() and
result = asDefinitionImpl(store)
)
}
/**
* Gets the indirect definition at a given indirection corresponding to this
* node, if any.
*
* See the comments on `Node.asDefinition` for examples.
*/
Expr asIndirectDefinition(int indirectionIndex) {
exists(StoreInstruction store |
this.(IndirectInstruction).hasInstructionAndIndirectionIndex(store, indirectionIndex) and
result = asDefinitionImpl(store)
)
}
/**
* Gets the indirect definition at some indirection corresponding to this
* node, if any.
*/
Expr asIndirectDefinition() { result = this.asIndirectDefinition(_) }
/**
* Gets the argument that defines this `DefinitionByReferenceNode`, if any.
*
@@ -372,7 +437,12 @@ class Node extends TIRDataFlowNode {
* `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is
* a partial definition of `&x`).
*/
Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() }
Expr asPartialDefinition() {
exists(PartialDefinitionNode pdn | this = pdn |
pdn.getIndirectionIndex() > 0 and
result = pdn.getDefinedExpr()
)
}
/**
* Gets an upper bound on the type of this node.
@@ -416,13 +486,6 @@ class Node extends TIRDataFlowNode {
}
}
private string toExprString(Node n) {
result = n.asExpr(0).toString()
or
not exists(n.asExpr()) and
result = n.asIndirectExpr(0, 1).toString() + " indirection"
}
/**
* A class that lifts pre-SSA dataflow nodes to regular dataflow nodes.
*/
@@ -485,37 +548,53 @@ Type stripPointer(Type t) {
result = t.(FunctionPointerIshType).getBaseType()
}
/**
* INTERNAL: Do not use.
*/
class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
int indirectionIndex;
Operand operand;
PostUpdateNodeImpl() { this = TPostUpdateNodeImpl(operand, indirectionIndex) }
override Declaration getFunction() { result = operand.getUse().getEnclosingFunction() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
/** Gets the operand associated with this node. */
Operand getOperand() { result = operand }
/** Gets the indirection index associated with this node. */
override int getIndirectionIndex() { result = indirectionIndex }
override Location getLocationImpl() { result = operand.getLocation() }
final override Node getPreUpdateNode() {
indirectionIndex > 0 and
hasOperandAndIndex(result, operand, indirectionIndex)
or
indirectionIndex = 0 and
result.asOperand() = operand
}
final override Expr getDefinedExpr() {
result = operand.getDef().getUnconvertedResultExpression()
}
}
/**
* INTERNAL: do not use.
*
* The node representing the value of a field after it has been updated.
*/
class PostFieldUpdateNode extends TPostFieldUpdateNode, PartialDefinitionNode {
int indirectionIndex;
class PostFieldUpdateNode extends PostUpdateNodeImpl {
FieldAddress fieldAddress;
PostFieldUpdateNode() { this = TPostFieldUpdateNode(fieldAddress, indirectionIndex) }
override Declaration getFunction() { result = fieldAddress.getUse().getEnclosingFunction() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
PostFieldUpdateNode() { operand = fieldAddress.getObjectAddressOperand() }
FieldAddress getFieldAddress() { result = fieldAddress }
Field getUpdatedField() { result = fieldAddress.getField() }
int getIndirectionIndex() { result = indirectionIndex }
override Node getPreUpdateNode() {
hasOperandAndIndex(result, pragma[only_bind_into](fieldAddress).getObjectAddressOperand(),
indirectionIndex)
}
override Expr getDefinedExpr() {
result = fieldAddress.getObjectAddress().getUnconvertedResultExpression()
}
override Location getLocationImpl() { result = fieldAddress.getLocation() }
Field getUpdatedField() { result = this.getFieldAddress().getField() }
override string toStringImpl() { result = this.getPreUpdateNode() + " [post update]" }
}
@@ -700,10 +779,12 @@ class IndirectParameterNode extends Node instanceof IndirectInstruction {
override Location getLocationImpl() { result = this.getParameter().getLocation() }
override string toStringImpl() {
result = this.getParameter().toString() + " indirection"
or
not exists(this.getParameter()) and
result = "this indirection"
exists(string prefix | prefix = stars(this) |
result = prefix + this.getParameter().toString()
or
not exists(this.getParameter()) and
result = prefix + "this"
)
}
}
@@ -751,13 +832,8 @@ class IndirectReturnNode extends Node {
* A node representing the indirection of a value after it
* has been returned from a function.
*/
class IndirectArgumentOutNode extends Node, TIndirectArgumentOutNode, PartialDefinitionNode {
ArgumentOperand operand;
int indirectionIndex;
IndirectArgumentOutNode() { this = TIndirectArgumentOutNode(operand, indirectionIndex) }
int getIndirectionIndex() { result = indirectionIndex }
class IndirectArgumentOutNode extends PostUpdateNodeImpl {
override ArgumentOperand operand;
int getArgumentIndex() {
exists(CallInstruction call | call.getArgumentOperand(result) = operand)
@@ -769,24 +845,16 @@ class IndirectArgumentOutNode extends Node, TIndirectArgumentOutNode, PartialDef
Function getStaticCallTarget() { result = this.getCallInstruction().getStaticCallTarget() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Declaration getFunction() { result = this.getCallInstruction().getEnclosingFunction() }
override Node getPreUpdateNode() { hasOperandAndIndex(result, operand, indirectionIndex) }
override string toStringImpl() {
// This string should be unique enough to be helpful but common enough to
// avoid storing too many different strings.
result = this.getStaticCallTarget().getName() + " output argument"
or
not exists(this.getStaticCallTarget()) and
result = "output argument"
exists(string prefix | if indirectionIndex > 0 then prefix = "" else prefix = "pointer to " |
// This string should be unique enough to be helpful but common enough to
// avoid storing too many different strings.
result = prefix + this.getStaticCallTarget().getName() + " output argument"
or
not exists(this.getStaticCallTarget()) and
result = prefix + "output argument"
)
}
override Location getLocationImpl() { result = operand.getLocation() }
override Expr getDefinedExpr() { result = operand.getDef().getUnconvertedResultExpression() }
}
/**
@@ -891,7 +959,8 @@ private Type getTypeImpl0(Type t, int indirectionIndex) {
*
* If `indirectionIndex` cannot be stripped off `t`, an `UnknownType` is returned.
*/
bindingset[indirectionIndex]
bindingset[t, indirectionIndex]
pragma[inline_late]
Type getTypeImpl(Type t, int indirectionIndex) {
result = getTypeImpl0(t, indirectionIndex)
or
@@ -943,7 +1012,7 @@ private module RawIndirectNodes {
}
override string toStringImpl() {
result = operandNode(this.getOperand()).toStringImpl() + " indirection"
result = stars(this) + operandNode(this.getOperand()).toStringImpl()
}
}
@@ -985,7 +1054,7 @@ private module RawIndirectNodes {
}
override string toStringImpl() {
result = instructionNode(this.getInstruction()).toStringImpl() + " indirection"
result = stars(this) + instructionNode(this.getInstruction()).toStringImpl()
}
}
@@ -1078,9 +1147,7 @@ class FinalParameterNode extends Node, TFinalParameterNode {
result instanceof UnknownDefaultLocation
}
override string toStringImpl() {
if indirectionIndex > 1 then result = p.toString() + " indirection" else result = p.toString()
}
override string toStringImpl() { result = stars(this) + p.toString() }
}
/**
@@ -1142,22 +1209,6 @@ private module GetConvertedResultExpression {
}
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
// For an expression such as `i += 2` we pretend that the generated
// `StoreInstruction` contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedAssignOperation tao |
result = tao.getExpr() and
instr = tao.getInstruction(any(AssignmentStoreTag tag))
)
or
// Similarly for `i++` and `++i` we pretend that the generated
// `StoreInstruction` is contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedCrementOperation tco |
result = tco.getExpr() and
instr = tco.getInstruction(any(CrementStoreTag tag))
)
or
// IR construction inserts an additional cast to a `size_t` on the extent
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
// a result for `getConvertedResultExpression`. We remap this here so that
@@ -1165,7 +1216,7 @@ private module GetConvertedResultExpression {
// represents the extent.
exists(TranslatedNonConstantAllocationSize tas |
result = tas.getExtent().getExpr() and
instr = tas.getInstruction(any(AllocationExtentConvertTag tag))
instr = tas.getInstruction(AllocationExtentConvertTag())
)
or
// There's no instruction that returns `ParenthesisExpr`, but some queries
@@ -1174,6 +1225,39 @@ private module GetConvertedResultExpression {
result = ttc.getExpr().(ParenthesisExpr) and
instr = ttc.getResult()
)
or
// Certain expressions generate `CopyValueInstruction`s only when they
// are needed. Examples of this include crement operations and compound
// assignment operations. For example:
// ```cpp
// int x = ...
// int y = x++;
// ```
// this generate IR like:
// ```
// r1(glval<int>) = VariableAddress[x] :
// r2(int) = Constant[0] :
// m3(int) = Store[x] : &:r1, r2
// r4(glval<int>) = VariableAddress[y] :
// r5(glval<int>) = VariableAddress[x] :
// r6(int) = Load[x] : &:r5, m3
// r7(int) = Constant[1] :
// r8(int) = Add : r6, r7
// m9(int) = Store[x] : &:r5, r8
// r11(int) = CopyValue : r6
// m12(int) = Store[y] : &:r4, r11
// ```
// When the `CopyValueInstruction` is not generated there is no instruction
// whose `getConvertedResultExpression` maps back to the expression. When
// such an instruction doesn't exist it means that the old value is not
// needed, and in that case the only value that will propagate forward in
// the program is the value that's been updated. So in those cases we just
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
exists(TranslatedCoreExpr tco |
tco.getInstruction(_) = instr and
tco.producesExprResult() and
result = asDefinitionImpl0(instr)
)
}
private Expr getConvertedResultExpressionImpl(Instruction instr) {
@@ -1182,6 +1266,75 @@ private module GetConvertedResultExpression {
not exists(getConvertedResultExpressionImpl0(instr)) and
result = instr.getConvertedResultExpression()
}
/**
* Gets the result for `node.asDefinition()` (when `node` is the instruction
* node that wraps `store`) in the cases where `store.getAst()` should not be
* used to define the result of `node.asDefinition()`.
*/
private Expr asDefinitionImpl0(StoreInstruction store) {
// For an expression such as `i += 2` we pretend that the generated
// `StoreInstruction` contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedAssignOperation tao |
store = tao.getInstruction(AssignmentStoreTag()) and
result = tao.getExpr()
)
or
// Similarly for `i++` and `++i` we pretend that the generated
// `StoreInstruction` is contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedCrementOperation tco |
store = tco.getInstruction(CrementStoreTag()) and
result = tco.getExpr()
)
}
/**
* Holds if the expression returned by `store.getAst()` should not be
* returned as the result of `node.asDefinition()` when `node` is the
* instruction node that wraps `store`.
*/
private predicate excludeAsDefinitionResult(StoreInstruction store) {
// Exclude the store to the temporary generated by a ternary expression.
exists(TranslatedConditionalExpr tce |
store = tce.getInstruction(ConditionValueFalseStoreTag())
or
store = tce.getInstruction(ConditionValueTrueStoreTag())
)
}
/**
* Gets the expression that represents the result of `StoreInstruction` for
* dataflow purposes.
*
* For example, consider the following example
* ```cpp
* int x = 42; // 1
* x = 34; // 2
* ++x; // 3
* x++; // 4
* x += 1; // 5
* int y = x += 2; // 6
* ```
* For (1) the result is `42`.
* For (2) the result is `x = 34`.
* For (3) the result is `++x`.
* For (4) the result is `x++`.
* For (5) the result is `x += 1`.
* For (6) there are two results:
* - For the `StoreInstruction` generated by `x += 2` the result
* is `x += 2`
* - For the `StoreInstruction` generated by `int y = ...` the result
* is also `x += 2`
*/
Expr asDefinitionImpl(StoreInstruction store) {
not exists(asDefinitionImpl0(store)) and
not excludeAsDefinitionResult(store) and
result = store.getAst().(Expr).getUnconverted()
or
result = asDefinitionImpl0(store)
}
}
private import GetConvertedResultExpression
@@ -1557,6 +1710,10 @@ abstract class PostUpdateNode extends Node {
* ```
*/
abstract private class PartialDefinitionNode extends PostUpdateNode {
/** Gets the indirection index of this node. */
abstract int getIndirectionIndex();
/** Gets the expression that is partially defined by this node. */
abstract Expr getDefinedExpr();
}
@@ -1571,6 +1728,8 @@ abstract private class PartialDefinitionNode extends PostUpdateNode {
* `getVariableAccess()` equal to `x`.
*/
class DefinitionByReferenceNode extends IndirectArgumentOutNode {
DefinitionByReferenceNode() { this.getIndirectionIndex() > 0 }
/** Gets the unconverted argument corresponding to this node. */
Expr getArgument() { result = this.getAddressOperand().getDef().getUnconvertedResultExpression() }
@@ -1622,9 +1781,7 @@ class VariableNode extends Node, TVariableNode {
result instanceof UnknownDefaultLocation
}
override string toStringImpl() {
if indirectionIndex = 1 then result = v.toString() else result = v.toString() + " indirection"
}
override string toStringImpl() { result = stars(this) + v.toString() }
}
/**
@@ -2084,6 +2241,25 @@ class Content extends TContent {
abstract predicate impliesClearOf(Content c);
}
private module ContentStars {
private int maxNumberOfIndirections() { result = max(any(Content c).getIndirectionIndex()) }
private string repeatStars(int n) {
n = 0 and result = ""
or
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
/**
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
* output for `c`.
*/
string contentStars(Content c) { result = repeatStars(c.getIndirectionIndex() - 1) }
}
private import ContentStars
/** A reference through a non-union instance field. */
class FieldContent extends Content, TFieldContent {
Field f;
@@ -2091,11 +2267,7 @@ class FieldContent extends Content, TFieldContent {
FieldContent() { this = TFieldContent(f, indirectionIndex) }
override string toString() {
indirectionIndex = 1 and result = f.toString()
or
indirectionIndex > 1 and result = f.toString() + " indirection"
}
override string toString() { result = contentStars(this) + f.toString() }
Field getField() { result = f }
@@ -2124,11 +2296,7 @@ class UnionContent extends Content, TUnionContent {
UnionContent() { this = TUnionContent(u, bytes, indirectionIndex) }
override string toString() {
indirectionIndex = 1 and result = u.toString()
or
indirectionIndex > 1 and result = u.toString() + " indirection"
}
override string toString() { result = contentStars(this) + u.toString() }
/** Gets a field of the underlying union of this `UnionContent`, if any. */
Field getAField() { result = u.getAField() and getFieldSize(result) = bytes }

View File

@@ -0,0 +1,24 @@
/**
* This file contains the class that implements the _debug_ version of
* `toString` for `Instruction` and `Operand` dataflow nodes.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import Node0ToString
private import DataFlowUtil
private class DebugNode0ToString extends Node0ToString {
DebugNode0ToString() {
// Silence warning about `this` not being bound.
exists(this)
}
override string instructionToString(Instruction i) { result = i.getDumpString() }
override string operandToString(Operand op) {
result = op.getDumpString() + " @ " + op.getUse().getResultId()
}
override string toExprString(Node n) { none() }
}

View File

@@ -1,668 +0,0 @@
/**
* INTERNAL: Do not use.
*
* An IR taint tracking library that uses an IR DataFlow configuration to track
* taint from user inputs as defined by `semmle.code.cpp.security.Security`.
*/
import cpp
import semmle.code.cpp.security.Security
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.ResolveCall
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.models.interfaces.Taint
private import semmle.code.cpp.models.interfaces.DataFlow
private import semmle.code.cpp.ir.dataflow.TaintTracking
private import semmle.code.cpp.ir.dataflow.TaintTracking2
private import semmle.code.cpp.ir.dataflow.TaintTracking3
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
/**
* A predictable instruction is one where an external user can predict
* the value. For example, a literal in the source code is considered
* predictable.
*/
private predicate predictableInstruction(Instruction instr) {
instr instanceof ConstantInstruction
or
instr instanceof StringConstantInstruction
or
// This could be a conversion on a string literal
predictableInstruction(instr.(UnaryInstruction).getUnary())
}
/**
* Functions that we should only allow taint to flow through (to the return
* value) if all but the source argument are 'predictable'. This is done to
* emulate the old security library's implementation rather than due to any
* strong belief that this is the right approach.
*
* Note that the list itself is not very principled; it consists of all the
* functions listed in the old security library's [default] `isPureFunction`
* that have more than one argument, but are not in the old taint tracking
* library's `returnArgument` predicate.
*/
predicate predictableOnlyFlow(string name) {
name =
[
"strcasestr", "strchnul", "strchr", "strchrnul", "strcmp", "strcspn", "strncmp", "strndup",
"strnlen", "strrchr", "strspn", "strstr", "strtod", "strtof", "strtol", "strtoll", "strtoq",
"strtoul"
]
}
private DataFlow::Node getNodeForSource(Expr source) {
isUserInput(source, _) and
result = getNodeForExpr(source)
}
private DataFlow::Node getNodeForExpr(Expr node) {
node = DataFlow::ExprFlowCached::asExprInternal(result)
or
// Some of the sources in `isUserInput` are intended to match the value of
// an expression, while others (those modeled below) are intended to match
// the taint that propagates out of an argument, like the `char *` argument
// to `gets`. It's impossible here to tell which is which, but the "access
// to argv" source is definitely not intended to match an output argument,
// and it causes false positives if we let it.
//
// This case goes together with the similar (but not identical) rule in
// `nodeIsBarrierIn`.
result = DataFlow::definitionByReferenceNodeFromArgument(node) and
not argv(node.(VariableAccess).getTarget())
}
private predicate conflatePointerAndPointee(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// Flow from `op` to `*op`.
exists(Operand operand, int indirectionIndex |
nodeHasOperand(nodeFrom, operand, indirectionIndex) and
nodeHasOperand(nodeTo, operand, indirectionIndex - 1)
)
or
// Flow from `instr` to `*instr`.
exists(Instruction instr, int indirectionIndex |
nodeHasInstruction(nodeFrom, instr, indirectionIndex) and
nodeHasInstruction(nodeTo, instr, indirectionIndex - 1)
)
}
private module DefaultTaintTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
conflatePointerAndPointee(nodeFrom, nodeTo)
}
}
private module DefaultTaintTrackingFlow = TaintTracking::Global<DefaultTaintTrackingConfig>;
private module ToGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
predicate isSink(DataFlow::Node sink) { sink.asVariable() instanceof GlobalOrNamespaceVariable }
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
or
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
}
predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
}
private module ToGlobalVarTaintTrackingFlow = TaintTracking::Global<ToGlobalVarTaintTrackingConfig>;
private module FromGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
// This set of sources should be reasonably small, which is good for
// performance since the set of sinks is very large.
ToGlobalVarTaintTrackingFlow::flowTo(source)
}
predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
// Additional step for flow out of variables. There is no flow _into_
// variables in this configuration, so this step only serves to take flow
// out of a variable that's a source.
readsVariable(n2.asInstruction(), n1.asVariable())
}
predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
}
private module FromGlobalVarTaintTrackingFlow =
TaintTracking::Global<FromGlobalVarTaintTrackingConfig>;
private predicate readsVariable(LoadInstruction load, Variable var) {
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
}
private predicate writesVariable(StoreInstruction store, Variable var) {
store.getDestinationAddress().(VariableAddressInstruction).getAstVariable() = var
}
/**
* A variable that has any kind of upper-bound check anywhere in the program. This is
* biased towards being inclusive because there are a lot of valid ways of doing an
* upper bounds checks if we don't consider where it occurs, for example:
* ```
* if (x < 10) { sink(x); }
*
* if (10 > y) { sink(y); }
*
* if (z > 10) { z = 10; }
* sink(z);
* ```
*/
// TODO: This coarse overapproximation, ported from the old taint tracking
// library, could be replaced with an actual semantic check that a particular
// variable _access_ is guarded by an upper-bound check. We probably don't want
// to do this right away since it could expose a lot of FPs that were
// previously suppressed by this predicate by coincidence.
private predicate hasUpperBoundsCheck(Variable var) {
exists(RelationalOperation oper, VariableAccess access |
oper.getAnOperand() = access and
access.getTarget() = var and
// Comparing to 0 is not an upper bound check
not oper.getAnOperand().getValue() = "0"
)
}
private predicate nodeIsBarrierEqualityCandidate(
DataFlow::Node node, Operand access, Variable checkedVar
) {
exists(Instruction instr | instr = node.asOperand().getDef() |
readsVariable(instr, checkedVar) and
any(IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
)
}
cached
private module Cached {
cached
predicate nodeIsBarrier(DataFlow::Node node) {
exists(Variable checkedVar, Instruction instr | instr = node.asOperand().getDef() |
readsVariable(instr, checkedVar) and
hasUpperBoundsCheck(checkedVar)
)
or
exists(Variable checkedVar, Operand access |
/*
* This node is guarded by a condition that forces the accessed variable
* to equal something else. For example:
* ```
* x = taintsource()
* if (x == 10) {
* taintsink(x); // not considered tainted
* }
* ```
*/
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
readsVariable(access.getDef(), checkedVar)
)
}
cached
predicate nodeIsBarrierIn(DataFlow::Node node) {
// don't use dataflow into taint sources, as this leads to duplicate results.
exists(Expr source | isUserInput(source, _) |
source = DataFlow::ExprFlowCached::asExprInternal(node)
or
// This case goes together with the similar (but not identical) rule in
// `getNodeForSource`.
node = DataFlow::definitionByReferenceNodeFromArgument(source)
)
or
// don't use dataflow into binary instructions if both operands are unpredictable
exists(BinaryInstruction iTo |
iTo = node.asInstruction() and
not predictableInstruction(iTo.getLeft()) and
not predictableInstruction(iTo.getRight()) and
// propagate taint from either the pointer or the offset, regardless of predictability
not iTo instanceof PointerArithmeticInstruction
)
or
// don't use dataflow through calls to pure functions if two or more operands
// are unpredictable
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
iTo = node.asInstruction() and
isPureFunction(iTo.getStaticCallTarget().getName()) and
iFrom1 = iTo.getAnArgument() and
iFrom2 = iTo.getAnArgument() and
not predictableInstruction(iFrom1) and
not predictableInstruction(iFrom2) and
iFrom1 != iFrom2
)
}
cached
Element adjustedSink(DataFlow::Node sink) {
// TODO: is it more appropriate to use asConvertedExpr here and avoid
// `getConversion*`? Or will that cause us to miss some cases where there's
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
// pretend there was flow to the converted `Expr` for the sake of
// compatibility.
sink.asExpr().getConversion*() = result
or
// For compatibility, send flow from arguments to parameters, even for
// functions with no body.
exists(FunctionCall call, int i |
sink.asExpr() = call.getArgument(pragma[only_bind_into](i)) and
result = resolveCall(call).getParameter(pragma[only_bind_into](i))
)
or
// For compatibility, send flow into a `Variable` if there is flow to any
// Load or Store of that variable.
exists(CopyInstruction copy |
copy.getSourceValue() = sink.asInstruction() and
(
readsVariable(copy, result) or
writesVariable(copy, result)
) and
not hasUpperBoundsCheck(result)
)
or
// For compatibility, send flow into a `NotExpr` even if it's part of a
// short-circuiting condition and thus might get skipped.
result.(NotExpr).getOperand() = sink.asExpr()
or
// Taint postfix and prefix crement operations when their operand is tainted.
result.(CrementOperation).getAnOperand() = sink.asExpr()
or
// Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted.
result.(AssignOperation).getAnOperand() = sink.asExpr()
or
result =
sink.asOperand()
.(SideEffectOperand)
.getUse()
.(ReadSideEffectInstruction)
.getArgumentDef()
.getUnconvertedResultExpression()
}
/**
* Step to return value of a modeled function when an input taints the
* dereference of the return value.
*/
cached
predicate additionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
exists(CallInstruction call, Function func, FunctionInput modelIn, FunctionOutput modelOut |
n1 = callInput(call, modelIn) and
(
func.(TaintFunction).hasTaintFlow(modelIn, modelOut)
or
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
) and
call.getStaticCallTarget() = func and
modelOut.isReturnValueDeref() and
call = n2.asInstruction()
)
}
}
private import Cached
/**
* Holds if `tainted` may contain taint from `source`.
*
* A tainted expression is either directly user input, or is
* computed from user input in a way that users can probably
* control the exact output of the computation.
*
* This doesn't include data flow through global variables.
* If you need that you must call `taintedIncludingGlobalVars`.
*/
cached
predicate tainted(Expr source, Element tainted) {
exists(DataFlow::Node sink |
DefaultTaintTrackingFlow::flow(getNodeForSource(source), sink) and
tainted = adjustedSink(sink)
)
}
/**
* Holds if `tainted` may contain taint from `source`, where the taint passed
* through a global variable named `globalVar`.
*
* A tainted expression is either directly user input, or is
* computed from user input in a way that users can probably
* control the exact output of the computation.
*
* This version gives the same results as tainted but also includes
* data flow through global variables.
*
* The parameter `globalVar` is the qualified name of the last global variable
* used to move the value from source to tainted. If the taint did not pass
* through a global variable, then `globalVar = ""`.
*/
cached
predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) {
tainted(source, tainted) and
globalVar = ""
or
exists(
DataFlow::VariableNode variableNode, GlobalOrNamespaceVariable global, DataFlow::Node sink
|
global = variableNode.getVariable() and
ToGlobalVarTaintTrackingFlow::flow(getNodeForSource(source), variableNode) and
FromGlobalVarTaintTrackingFlow::flow(variableNode, sink) and
tainted = adjustedSink(sink) and
global = globalVarFromId(globalVar)
)
}
/**
* Gets the global variable whose qualified name is `id`. Use this predicate
* together with `taintedIncludingGlobalVars`. Example:
*
* ```
* exists(string varName |
* taintedIncludingGlobalVars(source, tainted, varName) and
* var = globalVarFromId(varName)
* )
* ```
*/
GlobalOrNamespaceVariable globalVarFromId(string id) { id = result.getQualifiedName() }
/**
* Provides definitions for augmenting source/sink pairs with data-flow paths
* between them. From a `@kind path-problem` query, import this module in the
* global scope, extend `TaintTrackingConfiguration`, and use `taintedWithPath`
* in place of `tainted`.
*
* Importing this module will also import the query predicates that contain the
* taint paths.
*/
module TaintedWithPath {
private newtype TSingleton = MkSingleton()
/**
* A taint-tracking configuration that matches sources and sinks in the same
* way as the `tainted` predicate.
*
* Override `isSink` and `taintThroughGlobals` as needed, but do not provide
* a characteristic predicate.
*/
class TaintTrackingConfiguration extends TSingleton {
/** Override this to specify which elements are sources in this configuration. */
predicate isSource(Expr source) { exists(getNodeForSource(source)) }
/** Override this to specify which elements are sinks in this configuration. */
abstract predicate isSink(Element e);
/** Override this to specify which expressions are barriers in this configuration. */
predicate isBarrier(Expr e) { nodeIsBarrier(getNodeForExpr(e)) }
/**
* Override this predicate to `any()` to allow taint to flow through global
* variables.
*/
predicate taintThroughGlobals() { none() }
/** Gets a textual representation of this element. */
string toString() { result = "TaintTrackingConfiguration" }
}
private module AdjustedConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(TaintTrackingConfiguration cfg, Expr e |
cfg.isSource(e) and source = getNodeForExpr(e)
)
}
predicate isSink(DataFlow::Node sink) {
exists(TaintTrackingConfiguration cfg | cfg.isSink(adjustedSink(sink)))
}
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
conflatePointerAndPointee(n1, n2)
or
// Steps into and out of global variables
exists(TaintTrackingConfiguration cfg | cfg.taintThroughGlobals() |
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
or
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
)
or
additionalTaintStep(n1, n2)
}
predicate isBarrier(DataFlow::Node node) {
exists(TaintTrackingConfiguration cfg, Expr e | cfg.isBarrier(e) and node = getNodeForExpr(e))
}
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
predicate neverSkip(Node node) { none() }
}
private module AdjustedFlow = TaintTracking::Global<AdjustedConfig>;
/*
* A sink `Element` may map to multiple `DataFlowX::PathNode`s via (the
* inverse of) `adjustedSink`. For example, an `Expr` maps to all its
* conversions, and a `Variable` maps to all loads and stores from it. Because
* the path node is part of the tuple that constitutes the alert, this leads
* to duplicate alerts.
*
* To avoid showing duplicates, we edit the graph to replace the final node
* coming from the data-flow library with a node that matches exactly the
* `Element` sink that's requested.
*
* The same is done for sources.
*/
private newtype TPathNode =
TWrapPathNode(AdjustedFlow::PathNode n) or
// There's a single newtype constructor for both sources and sinks since
// that makes it easiest to deal with the case where source = sink.
TEndpointPathNode(Element e) {
exists(DataFlow::Node sourceNode, DataFlow::Node sinkNode |
AdjustedFlow::flow(sourceNode, sinkNode)
|
sourceNode = getNodeForExpr(e) and
exists(TaintTrackingConfiguration ttCfg | ttCfg.isSource(e))
or
e = adjustedSink(sinkNode) and
exists(TaintTrackingConfiguration ttCfg | ttCfg.isSink(e))
)
}
/** An opaque type used for the nodes of a data-flow path. */
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
}
/**
* INTERNAL: Do not use.
*/
module Private {
/** Gets a predecessor `PathNode` of `pathNode`, if any. */
PathNode getAPredecessor(PathNode pathNode) { edges(result, pathNode) }
/** Gets the element that `pathNode` wraps, if any. */
Element getElementFromPathNode(PathNode pathNode) {
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
result = node.asInstruction().getAst()
or
result = node.asOperand().getDef().getAst()
)
or
result = pathNode.(EndpointPathNode).inner()
}
}
private class WrapPathNode extends PathNode, TWrapPathNode {
AdjustedFlow::PathNode inner() { this = TWrapPathNode(result) }
override string toString() { result = this.inner().toString() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.inner().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
private class EndpointPathNode extends PathNode, TEndpointPathNode {
Expr inner() { this = TEndpointPathNode(result) }
override string toString() { result = this.inner().toString() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.inner()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
/** A PathNode whose `Element` is a source. It may also be a sink. */
private class InitialPathNode extends EndpointPathNode {
InitialPathNode() { exists(TaintTrackingConfiguration cfg | cfg.isSource(this.inner())) }
}
/** A PathNode whose `Element` is a sink. It may also be a source. */
private class FinalPathNode extends EndpointPathNode {
FinalPathNode() { exists(TaintTrackingConfiguration cfg | cfg.isSink(this.inner())) }
}
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) {
AdjustedFlow::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner())
or
// To avoid showing trivial-looking steps, we _replace_ the last node instead
// of adding an edge out of it.
exists(WrapPathNode sinkNode |
AdjustedFlow::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
)
or
// Same for the first node
exists(WrapPathNode sourceNode |
AdjustedFlow::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and
sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner())
)
or
// Finally, handle the case where the path goes directly from a source to a
// sink, meaning that they both need to be translated.
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
AdjustedFlow::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and
sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner()) and
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
)
}
/**
* Holds if there is flow from `arg` to `out` across a call that can by summarized by the flow
* from `par` to `ret` within it, in the graph of data flow path explanations.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
AdjustedFlow::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
ret.(WrapPathNode).inner(), out.(WrapPathNode).inner())
or
// To avoid showing trivial-looking steps, we _replace_ the last node instead
// of adding an edge out of it.
exists(WrapPathNode sinkNode |
AdjustedFlow::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
ret.(WrapPathNode).inner(), sinkNode.inner()) and
out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
)
or
// Same for the first node
exists(WrapPathNode sourceNode |
AdjustedFlow::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
ret.(WrapPathNode).inner(), out.(WrapPathNode).inner()) and
sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner())
)
or
// Finally, handle the case where the path goes directly from a source to a
// sink, meaning that they both need to be translated.
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
AdjustedFlow::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
ret.(WrapPathNode).inner(), sinkNode.inner()) and
sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner()) and
out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
)
}
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
}
/**
* Holds if `tainted` may contain taint from `source`, where `sourceNode` and
* `sinkNode` are the corresponding `PathNode`s that can be used in a query
* to provide path explanations. Extend `TaintTrackingConfiguration` to use
* this predicate.
*
* A tainted expression is either directly user input, or is computed from
* user input in a way that users can probably control the exact output of
* the computation.
*/
predicate taintedWithPath(Expr source, Element tainted, PathNode sourceNode, PathNode sinkNode) {
exists(DataFlow::Node flowSource, DataFlow::Node flowSink |
source = sourceNode.(InitialPathNode).inner() and
flowSource = getNodeForExpr(source) and
AdjustedFlow::flow(flowSource, flowSink) and
tainted = adjustedSink(flowSink) and
tainted = sinkNode.(FinalPathNode).inner()
)
}
private predicate isGlobalVariablePathNode(WrapPathNode n) {
n.inner().getNode().asVariable() instanceof GlobalOrNamespaceVariable
or
n.inner().getNode().asIndirectVariable() instanceof GlobalOrNamespaceVariable
}
private predicate edgesWithoutGlobals(PathNode a, PathNode b) {
edges(a, b) and
not isGlobalVariablePathNode(a) and
not isGlobalVariablePathNode(b)
}
/**
* Holds if `tainted` can be reached from a taint source without passing
* through a global variable.
*/
predicate taintedWithoutGlobals(Element tainted) {
exists(PathNode sourceNode, FinalPathNode sinkNode |
AdjustedConfig::isSource(sourceNode.(WrapPathNode).inner().getNode()) and
edgesWithoutGlobals+(sourceNode, sinkNode) and
tainted = sinkNode.inner()
)
}
}

View File

@@ -0,0 +1,53 @@
/**
* This file imports the class that is used to construct the strings used by
* `Node.ToString`.
*
* Normally, this file should just import `NormalNode0ToString` to compute the
* efficient `toString`, but for debugging purposes one can import
* `DebugPrinting.qll` to better correlate the dataflow nodes with their
* underlying instructions and operands.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import DataFlowUtil
import NormalNode0ToString // Change this import to control which version should be used.
/** An abstract class to control the behavior of `Node.toString`. */
abstract class Node0ToString extends Unit {
/**
* Gets the string that should be used by `OperandNode.toString` to print the
* dataflow node whose underlying operand is `op.`
*/
abstract string operandToString(Operand op);
/**
* Gets the string that should be used by `InstructionNode.toString` to print
* the dataflow node whose underlying instruction is `instr`.
*/
abstract string instructionToString(Instruction i);
/**
* Gets the string representation of the `Expr` associated with `n`, if any.
*/
abstract string toExprString(Node n);
}
/**
* Gets the string that should be used by `OperandNode.toString` to print the
* dataflow node whose underlying operand is `op.`
*/
string operandToString(Operand op) { result = any(Node0ToString s).operandToString(op) }
/**
* Gets the string that should be used by `InstructionNode.toString` to print
* the dataflow node whose underlying instruction is `instr`.
*/
string instructionToString(Instruction instr) {
result = any(Node0ToString s).instructionToString(instr)
}
/**
* Gets the string representation of the `Expr` associated with `n`, if any.
*/
string toExprString(Node n) { result = any(Node0ToString s).toExprString(n) }

View File

@@ -0,0 +1,36 @@
/**
* This file contains the class that implements the non-debug version of
* `toString` for `Instruction` and `Operand` dataflow nodes.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import Node0ToString
private import DataFlowUtil
private import DataFlowPrivate
private class NormalNode0ToString extends Node0ToString {
NormalNode0ToString() {
// Silence warning about `this` not being bound.
exists(this)
}
override string instructionToString(Instruction i) {
if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = i.getAst().toString()
}
override string operandToString(Operand op) {
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
override string toExprString(Node n) {
result = n.asExpr(0).toString()
or
not exists(n.asExpr()) and
result = stars(n) + n.asIndirectExpr(0, 1).toString()
}
}

View File

@@ -0,0 +1,12 @@
private import cpp
private import semmle.code.cpp.ir.IR
private import SsaInternals as Ssa
/**
* A property provider that hides all instructions and operands that are not relevant for IR dataflow.
*/
class DataFlowRelevantIRPropertyProvider extends IRPropertyProvider {
override predicate shouldPrintOperand(Operand operand) { not Ssa::ignoreOperand(operand) }
override predicate shouldPrintInstruction(Instruction instr) { not Ssa::ignoreInstruction(instr) }
}

View File

@@ -1,6 +1,7 @@
private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import SsaInternals as Ssa
private import PrintIRUtilities
@@ -33,9 +34,9 @@ private string getNodeProperty(Node node, string key) {
key = "flow" and
result =
strictconcat(string flow, boolean to, int order1, int order2 |
flow = getFromFlow(node, order1, order2) + "->" + starsForNode(node) + "@" and to = false
flow = getFromFlow(node, order1, order2) + "->" + stars(node) + "@" and to = false
or
flow = starsForNode(node) + "@->" + getToFlow(node, order1, order2) and to = true
flow = stars(node) + "@->" + getToFlow(node, order1, order2) and to = true
|
flow, ", " order by to, order1, order2, flow
)
@@ -59,8 +60,4 @@ class LocalFlowPropertyProvider extends IRPropertyProvider {
result = getNodeProperty(node, key)
)
}
override predicate shouldPrintOperand(Operand operand) { not Ssa::ignoreOperand(operand) }
override predicate shouldPrintInstruction(Instruction instr) { not Ssa::ignoreInstruction(instr) }
}

View File

@@ -7,37 +7,14 @@ private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private string stars(int k) {
k =
[0 .. max([
any(RawIndirectInstruction n).getIndirectionIndex(),
any(RawIndirectOperand n).getIndirectionIndex()
]
)] and
(if k = 0 then result = "" else result = "*" + stars(k - 1))
}
string starsForNode(Node node) {
exists(int indirectionIndex |
node.(IndirectInstruction).hasInstructionAndIndirectionIndex(_, indirectionIndex) or
node.(IndirectOperand).hasOperandAndIndirectionIndex(_, indirectionIndex)
|
result = stars(indirectionIndex)
)
or
not node instanceof IndirectInstruction and
not node instanceof IndirectOperand and
result = ""
}
private Instruction getInstruction(Node n, string stars) {
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
stars = starsForNode(n)
stars = stars(n)
}
private Operand getOperand(Node n, string stars) {
result = [n.asOperand(), n.(RawIndirectOperand).getOperand()] and
stars = starsForNode(n)
stars = stars(n)
}
/**

View File

@@ -417,60 +417,42 @@ class BaseCallVariable extends AbstractBaseSourceVariable, TBaseCallVariable {
override CppType getLanguageType() { result = getResultLanguageType(call) }
}
/**
* Holds if the value pointed to by `operand` can potentially be
* modified be the caller.
*/
predicate isModifiableByCall(ArgumentOperand operand, int indirectionIndex) {
exists(CallInstruction call, int index, CppType type |
indirectionIndex = [1 .. countIndirectionsForCppType(type)] and
type = getLanguageType(operand) and
call.getArgumentOperand(index) = operand and
if index = -1
then
// A qualifier is "modifiable" if:
// 1. the member function is not const specified, or
// 2. the member function is `const` specified, but returns a pointer or reference
// type that is non-const.
//
// To see why this is necessary, consider the following function:
// ```
// struct C {
// void* data_;
// void* data() const { return data; }
// };
// ...
// C c;
// memcpy(c.data(), source, 16)
// ```
// the data pointed to by `c.data_` is potentially modified by the call to `memcpy` even though
// `C::data` has a const specifier. So we further place the restriction that the type returned
// by `call` should not be of the form `const T*` (for some deeply const type `T`).
if call.getStaticCallTarget() instanceof Cpp::ConstMemberFunction
then
exists(PointerOrArrayOrReferenceType resultType |
resultType = call.getResultType() and
not resultType.isDeeplyConstBelow()
)
else any()
else
// An argument is modifiable if it's a non-const pointer or reference type.
isModifiableAt(type, indirectionIndex)
)
}
private module IsModifiableAtImpl {
pragma[nomagic]
private predicate isUnderlyingIndirectionType(Type t) {
t = any(Indirection ind).getUnderlyingType()
}
/**
* Holds if `t` is a pointer or reference type that supports at least `indirectionIndex` number
* of indirections, and the `indirectionIndex` indirection cannot be modfiied by passing a
* value of `t` to a function.
*/
private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
indirectionIndex = [1 .. countIndirectionsForCppType(cppType)] and
(
exists(Type pointerType, Type base, Type t |
pointerType = t.getUnderlyingType() and
pointerType = any(Indirection ind).getUnderlyingType() and
cppType.hasType(t, _) and
/**
* Holds if the `indirectionIndex`'th dereference of a value of type
* `cppType` is a type that can be modified (either by modifying the value
* itself or one of its fields if it's a class type).
*
* For example, a value of type `const int* const` cannot be modified
* at any indirection index (because it's a constant pointer to constant
* data), and a value of type `int *const *` is modifiable at indirection index
* 2 only.
*
* A value of type `const S2* s2` where `s2` is
* ```cpp
* struct S { int x; }
* ```
* can be modified at indirection index 1. This is to ensure that we generate
* a `PostUpdateNode` for the argument corresponding to the `s2` parameter in
* an example such as:
* ```cpp
* void set_field(const S2* s2)
* {
* s2->s->x = 42;
* }
* ```
*/
bindingset[cppType, indirectionIndex]
pragma[inline_late]
private predicate impl(CppType cppType, int indirectionIndex) {
exists(Type pointerType, Type base |
isUnderlyingIndirectionType(pointerType) and
cppType.hasUnderlyingType(pointerType, _) and
base = getTypeImpl(pointerType, indirectionIndex)
|
// The value cannot be modified if it has a const specifier,
@@ -480,28 +462,114 @@ private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
// one of the members was modified.
exists(base.stripType().(Cpp::Class).getAField())
)
}
/**
* Holds if `cppType` is modifiable with an indirection index of at least 1.
*
* This predicate factored out into a separate predicate for two reasons:
* - This predicate needs to be recursive because, if a type is modifiable
* at indirection `i`, then it's also modifiable at indirection index `i+1`
* (because the pointer could be completely re-assigned at indirection `i`).
* - We special-case indirection index `0` so that pointer arguments that can
* be modified at some index always have a `PostUpdateNode` at indiretion
* index 0 even though the 0'th indirection can never be modified by a
* callee.
*/
private predicate isModifiableAtImplAtLeast1(CppType cppType, int indirectionIndex) {
indirectionIndex = [1 .. countIndirectionsForCppType(cppType)] and
(
impl(cppType, indirectionIndex)
or
// If the `indirectionIndex`'th dereference of a type can be modified
// then so can the `indirectionIndex + 1`'th dereference.
isModifiableAtImplAtLeast1(cppType, indirectionIndex - 1)
)
}
/**
* Holds if `cppType` is modifiable at indirection index 0.
*
* In reality, the 0'th indirection of a pointer (i.e., the pointer itself)
* can never be modified by a callee, but it is sometimes useful to be able
* to specify the value of the pointer, as its coming out of a function, as
* a source of dataflow since the shared library's reverse-read mechanism
* then ensures that field-flow is accounted for.
*/
private predicate isModifiableAtImplAt0(CppType cppType) { impl(cppType, 0) }
/**
* Holds if `t` is a pointer or reference type that supports at least
* `indirectionIndex` number of indirections, and the `indirectionIndex`
* indirection cannot be modfiied by passing a value of `t` to a function.
*/
private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
isModifiableAtImplAtLeast1(cppType, indirectionIndex)
or
// If the `indirectionIndex`'th dereference of a type can be modified
// then so can the `indirectionIndex + 1`'th dereference.
isModifiableAtImpl(cppType, indirectionIndex - 1)
)
indirectionIndex = 0 and
isModifiableAtImplAt0(cppType)
}
/**
* Holds if `t` is a type with at least `indirectionIndex` number of
* indirections, and the `indirectionIndex` indirection can be modified by
* passing a value of type `t` to a function function.
*/
bindingset[indirectionIndex]
predicate isModifiableAt(CppType cppType, int indirectionIndex) {
isModifiableAtImpl(cppType, indirectionIndex)
or
exists(PointerWrapper pw, Type t |
cppType.hasType(t, _) and
t.stripType() = pw and
not pw.pointsToConst()
)
}
/**
* Holds if the value pointed to by `operand` can potentially be
* modified be the caller.
*/
predicate isModifiableByCall(ArgumentOperand operand, int indirectionIndex) {
exists(CallInstruction call, int index, CppType type |
indirectionIndex = [0 .. countIndirectionsForCppType(type)] and
type = getLanguageType(operand) and
call.getArgumentOperand(index) = operand and
if index = -1
then
// A qualifier is "modifiable" if:
// 1. the member function is not const specified, or
// 2. the member function is `const` specified, but returns a pointer or reference
// type that is non-const.
//
// To see why this is necessary, consider the following function:
// ```
// struct C {
// void* data_;
// void* data() const { return data; }
// };
// ...
// C c;
// memcpy(c.data(), source, 16)
// ```
// the data pointed to by `c.data_` is potentially modified by the call to `memcpy` even though
// `C::data` has a const specifier. So we further place the restriction that the type returned
// by `call` should not be of the form `const T*` (for some deeply const type `T`).
if call.getStaticCallTarget() instanceof Cpp::ConstMemberFunction
then
exists(PointerOrArrayOrReferenceType resultType |
resultType = call.getResultType() and
not resultType.isDeeplyConstBelow()
)
else any()
else
// An argument is modifiable if it's a non-const pointer or reference type.
isModifiableAt(type, indirectionIndex)
)
}
}
/**
* Holds if `t` is a type with at least `indirectionIndex` number of indirections,
* and the `indirectionIndex` indirection can be modified by passing a value of
* type `t` to a function function.
*/
bindingset[indirectionIndex]
predicate isModifiableAt(CppType cppType, int indirectionIndex) {
isModifiableAtImpl(cppType, indirectionIndex)
or
exists(PointerWrapper pw, Type t |
cppType.hasType(t, _) and
t.stripType() = pw and
not pw.pointsToConst()
)
}
import IsModifiableAtImpl
abstract class BaseSourceVariableInstruction extends Instruction {
/** Gets the base source variable accessed by this instruction. */

View File

@@ -1,4 +1,6 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -12,6 +14,8 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -51,7 +55,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract class Configuration extends DataFlow::Configuration {
abstract deprecated class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -1,4 +1,6 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -12,6 +14,8 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -51,7 +55,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract class Configuration extends DataFlow::Configuration {
abstract deprecated class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -1,4 +1,6 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -12,6 +14,8 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -51,7 +55,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract class Configuration extends DataFlow::Configuration {
abstract deprecated class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -227,7 +227,7 @@ class CppType extends TCppType {
predicate hasType(Type type, boolean isGLValue) { none() }
/**
* Holds if this type represents the C++ type `type`. If `isGLValue` is `true`, then this type
* Holds if this type represents the C++ unspecified type `type`. If `isGLValue` is `true`, then this type
* represents a glvalue of type `type`. Otherwise, it represents a prvalue of type `type`.
*/
final predicate hasUnspecifiedType(Type type, boolean isGLValue) {
@@ -236,6 +236,18 @@ class CppType extends TCppType {
type = specifiedType.getUnspecifiedType()
)
}
/**
* Holds if this type represents the C++ type `type` (after resolving
* typedefs). If `isGLValue` is `true`, then this type represents a glvalue
* of type `type`. Otherwise, it represents a prvalue of type `type`.
*/
final predicate hasUnderlyingType(Type type, boolean isGLValue) {
exists(Type typedefType |
this.hasType(typedefType, isGLValue) and
type = typedefType.getUnderlyingType()
)
}
}
/**

View File

@@ -9,8 +9,9 @@
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.Taint
pragma[nomagic]
private Type stripTopLevelSpecifiersOnly(Type t) {
result = stripTopLevelSpecifiersOnly(t.(SpecifiedType).getBaseType())
result = stripTopLevelSpecifiersOnly(pragma[only_bind_out](t.(SpecifiedType).getBaseType()))
or
result = t and
not t instanceof SpecifiedType

View File

@@ -25,4 +25,8 @@ module CppLangImplConstant implements LangSig<Sem, FloatDelta> {
* Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
*/
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
predicate includeConstantBounds() { any() }
predicate includeRelativeBounds() { none() }
}

View File

@@ -173,11 +173,11 @@ private module ModulusAnalysisInstantiated implements ModulusAnalysisSig<Sem> {
}
module ConstantStage =
RangeStage<SemLocation, Sem, FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
RangeStage<SemLocation, Sem, FloatDelta, AllBounds, FloatOverflow, CppLangImplConstant,
SignAnalysis, ModulusAnalysisInstantiated>;
module RelativeStage =
RangeStage<SemLocation, Sem, FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
RangeStage<SemLocation, Sem, FloatDelta, AllBounds, FloatOverflow, CppLangImplRelative,
SignAnalysis, ModulusAnalysisInstantiated>;
private newtype TSemReason =

View File

@@ -57,4 +57,8 @@ module CppLangImplRelative implements LangSig<Sem, FloatDelta> {
* Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
*/
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
predicate includeConstantBounds() { none() }
predicate includeRelativeBounds() { any() }
}

View File

@@ -45,7 +45,7 @@ class SecurityOptions extends string {
/**
* The argument of the given function is filled in from user input.
*/
predicate userInputArgument(FunctionCall functionCall, int arg) {
deprecated predicate userInputArgument(FunctionCall functionCall, int arg) {
exists(string fname |
functionCall.getTarget().hasGlobalOrStdName(fname) and
exists(functionCall.getArgument(arg)) and
@@ -73,7 +73,7 @@ class SecurityOptions extends string {
/**
* The return value of the given function is filled in from user input.
*/
predicate userInputReturned(FunctionCall functionCall) {
deprecated predicate userInputReturned(FunctionCall functionCall) {
exists(string fname |
functionCall.getTarget().getName() = fname and
(
@@ -91,12 +91,8 @@ class SecurityOptions extends string {
/**
* DEPRECATED: Users should override `userInputReturned()` instead.
*
* note: this function is not formally tagged as `deprecated` since the
* new `userInputReturned` uses it to provide compatibility with older
* custom SecurityOptions.qll files.
*/
predicate userInputReturn(string function) { none() }
deprecated predicate userInputReturn(string function) { none() }
/**
* The argument of the given function is used for running a process or loading
@@ -117,7 +113,7 @@ class SecurityOptions extends string {
* computed from user input. Such expressions are treated as
* sources of taint.
*/
predicate isUserInput(Expr expr, string cause) {
deprecated predicate isUserInput(Expr expr, string cause) {
exists(FunctionCall fc, int i |
this.userInputArgument(fc, i) and
expr = fc.getArgument(i) and
@@ -178,17 +174,17 @@ predicate argv(Parameter argv) {
predicate isPureFunction(string name) { exists(SecurityOptions opts | opts.isPureFunction(name)) }
/** Convenience accessor for SecurityOptions.userInputArgument */
predicate userInputArgument(FunctionCall functionCall, int arg) {
deprecated predicate userInputArgument(FunctionCall functionCall, int arg) {
exists(SecurityOptions opts | opts.userInputArgument(functionCall, arg))
}
/** Convenience accessor for SecurityOptions.userInputReturn */
predicate userInputReturned(FunctionCall functionCall) {
deprecated predicate userInputReturned(FunctionCall functionCall) {
exists(SecurityOptions opts | opts.userInputReturned(functionCall))
}
/** Convenience accessor for SecurityOptions.isUserInput */
predicate isUserInput(Expr expr, string cause) {
deprecated predicate isUserInput(Expr expr, string cause) {
exists(SecurityOptions opts | opts.isUserInput(expr, cause))
}

View File

@@ -23,7 +23,7 @@ class CustomSecurityOptions extends SecurityOptions {
none() // rules to match custom functions replace this line
}
override predicate userInputArgument(FunctionCall functionCall, int arg) {
deprecated override predicate userInputArgument(FunctionCall functionCall, int arg) {
SecurityOptions.super.userInputArgument(functionCall, arg)
or
exists(string fname |
@@ -36,7 +36,7 @@ class CustomSecurityOptions extends SecurityOptions {
)
}
override predicate userInputReturned(FunctionCall functionCall) {
deprecated override predicate userInputReturned(FunctionCall functionCall) {
SecurityOptions.super.userInputReturned(functionCall)
or
exists(string fname |

View File

@@ -1,10 +0,0 @@
/**
* Support for tracking tainted data through the program. This is an alias for
* `semmle.code.cpp.ir.dataflow.DefaultTaintTracking` provided for backwards
* compatibility.
*
* Prefer to use `semmle.code.cpp.dataflow.TaintTracking` or
* `semmle.code.cpp.ir.dataflow.TaintTracking` when designing new queries.
*/
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking

View File

@@ -1,654 +0,0 @@
/**
* DEPRECATED: we now use `semmle.code.cpp.ir.dataflow.DefaultTaintTracking`,
* which is based on the IR but designed to behave similarly to this old
* library.
*
* Provides the implementation of `semmle.code.cpp.security.TaintTracking`. Do
* not import this file directly.
*/
import cpp
import Security
/** Expressions that change the value of a variable */
private predicate valueSource(Expr expr) {
exists(AssignExpr ae | expr = ae.getLValue())
or
exists(FunctionCall fc, int i |
userInputArgument(fc, i) and
expr = fc.getArgument(i)
)
or
exists(FunctionCall c, int arg |
copyValueBetweenArguments(c.getTarget(), _, arg) and
expr = c.getArgument(arg)
)
or
exists(FunctionCall c, int arg |
c.getTarget().getParameter(arg).getType() instanceof ReferenceType and
expr = c.getArgument(arg)
)
}
/** Expressions that are inside an expression that changes the value of a variable */
private predicate insideValueSource(Expr expr) {
valueSource(expr)
or
insideValueSource(expr.getParent()) and
// A modification of array[offset] does not modify offset
not expr.getParent().(ArrayExpr).getArrayOffset() = expr
}
private predicate isPointer(Type type) {
type instanceof PointerType or
isPointer(type.(ReferenceType).getBaseType())
}
/**
* Tracks data flow from src to dest.
* If this is used in the left side of an assignment src and dest should be swapped
*/
private predicate moveToDependingOnSide(Expr src, Expr dest) {
exists(ParenthesisExpr e |
src = e.getAChild() and
dest = e
)
or
exists(ArrayExpr e |
src = e.getArrayBase() and
dest = e
)
or
exists(PointerDereferenceExpr e |
src = e.getOperand() and
dest = e
)
or
exists(AddressOfExpr e |
src = e.getOperand() and
dest = e
)
or
// if var+offset is tainted, then so is var
exists(VariableAccess base, BinaryOperation binop |
dest = binop and
(base = binop.getLeftOperand() or base = binop.getRightOperand()) and
isPointer(base.getType()) and
base.getTarget() instanceof LocalScopeVariable and
src = base and
// flow through pointer-pointer subtraction is dubious, the result should be
// a number bounded by the size of the pointed-to thing.
not binop instanceof PointerDiffExpr
)
or
exists(UnaryOperation unop |
dest = unop and
unop.getAnOperand() = src
)
or
exists(BinaryOperation binop |
dest = binop and
binop.getLeftOperand() = src and
predictable(binop.getRightOperand())
)
or
exists(BinaryOperation binop |
dest = binop and
binop.getRightOperand() = src and
predictable(binop.getLeftOperand())
)
or
exists(Cast cast |
dest = cast and
src = cast.getExpr()
)
or
exists(ConditionalExpr cond |
cond = dest and
(
cond.getThen() = src or
cond.getElse() = src
)
)
}
/**
* Track value flow between functions.
* Handles the following cases:
* - If an argument to a function is tainted, all the usages of the parameter inside the function are tainted
* - If a function obtains input from the user internally and returns it, all calls to the function are tainted
* - If an argument to a function is tainted and that parameter is returned, all calls to the function are not tainted
* (this is done to avoid false positives). Because of this we need to track if the tainted element came from an argument
* or not, and for that we use destFromArg
*/
deprecated private predicate betweenFunctionsValueMoveTo(
Element src, Element dest, boolean destFromArg
) {
not unreachable(src) and
not unreachable(dest) and
(
exists(Call call, int i |
src = call.getArgument(i) and
resolveCallWithParam(call, _, i, dest) and
destFromArg = true
)
or
// Only move the return of the function to the function itself if the value didn't came from an
// argument, or else we would taint all the calls to one function if one argument is tainted
// somewhere
exists(Function f, ReturnStmt ret |
ret.getEnclosingFunction() = f and
src = ret.getExpr() and
destFromArg = false and
dest = f
)
or
exists(Call call, Function f |
f = resolveCall(call) and
src = f and
dest = call and
destFromArg = false
)
or
// If a parameter of type reference is tainted inside a function, taint the argument too
exists(Call call, int pi, Parameter p |
resolveCallWithParam(call, _, pi, p) and
p.getType() instanceof ReferenceType and
src = p and
dest = call.getArgument(pi) and
destFromArg = false
)
)
}
// predicate folding for proper join-order
// bad magic: pushes down predicate that ruins join-order
pragma[nomagic]
deprecated private predicate resolveCallWithParam(Call call, Function called, int i, Parameter p) {
called = resolveCall(call) and
p = called.getParameter(i)
}
/** A variable for which flow through is allowed. */
deprecated library class FlowVariable extends Variable {
FlowVariable() {
(
this instanceof LocalScopeVariable or
this instanceof GlobalOrNamespaceVariable
) and
not argv(this)
}
}
/** A local scope variable for which flow through is allowed. */
deprecated library class FlowLocalScopeVariable extends Variable {
FlowLocalScopeVariable() { this instanceof LocalScopeVariable }
}
deprecated private predicate insideFunctionValueMoveTo(Element src, Element dest) {
not unreachable(src) and
not unreachable(dest) and
(
// Taint all variable usages when one is tainted
// This function taints global variables but doesn't taint from a global variable (see globalVariableValueMoveTo)
exists(FlowLocalScopeVariable v |
src = v and
dest = v.getAnAccess() and
not insideValueSource(dest)
)
or
exists(FlowVariable v |
src = v.getAnAccess() and
dest = v and
insideValueSource(src)
)
or
// Taint all union usages when one is tainted
// This function taints global variables but doesn't taint from a global variable (see globalVariableValueMoveTo)
exists(FlowLocalScopeVariable v, FieldAccess a |
unionAccess(v, _, a) and
src = v and
dest = a and
not insideValueSource(dest)
)
or
exists(FlowVariable v, FieldAccess a |
unionAccess(v, _, a) and
src = a and
dest = v and
insideValueSource(src)
)
or
// If a pointer is tainted, taint the original variable
exists(FlowVariable p, FlowVariable v, AddressOfExpr e |
p.getAnAssignedValue() = e and
e.getOperand() = v.getAnAccess() and
src = p and
dest = v
)
or
// If a reference is tainted, taint the original variable
exists(FlowVariable r, FlowVariable v |
r.getType() instanceof ReferenceType and
r.getInitializer().getExpr() = v.getAnAccess() and
src = r and
dest = v
)
or
exists(Variable var |
var = dest and
var.getInitializer().getExpr() = src
)
or
exists(AssignExpr ae |
src = ae.getRValue() and
dest = ae.getLValue()
)
or
exists(CommaExpr comma |
comma = dest and
comma.getRightOperand() = src
)
or
exists(FunctionCall c, int sourceArg, int destArg |
copyValueBetweenArguments(c.getTarget(), sourceArg, destArg) and
// Only consider copies from `printf`-like functions if the format is a string
(
exists(FormattingFunctionCall ffc, FormatLiteral format |
ffc = c and
format = ffc.getFormat() and
format.getConversionChar(sourceArg - ffc.getTarget().getNumberOfParameters()) = ["s", "S"]
)
or
not c.(FormattingFunctionCall).getFormat() instanceof FormatLiteral
or
not c instanceof FormattingFunctionCall
) and
src = c.getArgument(sourceArg) and
dest = c.getArgument(destArg)
)
or
exists(FunctionCall c, int sourceArg |
returnArgument(c.getTarget(), sourceArg) and
src = c.getArgument(sourceArg) and
dest = c
)
or
exists(FormattingFunctionCall formattingSend, int arg, FormatLiteral format |
dest = formattingSend and
formattingSend.getArgument(arg) = src and
format = formattingSend.getFormat() and
format.getConversionChar(arg - formattingSend.getTarget().getNumberOfParameters()) =
["s", "S", "@"]
)
or
// Expressions computed from tainted data are also tainted
exists(FunctionCall call | dest = call and isPureFunction(call.getTarget().getName()) |
call.getAnArgument() = src and
forall(Expr arg | arg = call.getAnArgument() | arg = src or predictable(arg)) and
// flow through `strlen` tends to cause dubious results, if the length is
// bounded.
not call.getTarget().getName() = "strlen"
)
or
exists(Element a, Element b |
moveToDependingOnSide(a, b) and
if insideValueSource(a) then (src = b and dest = a) else (src = a and dest = b)
)
)
}
/**
* Handles data flow from global variables to its usages.
* The tainting for the global variable itself is done at insideFunctionValueMoveTo.
*/
private predicate globalVariableValueMoveTo(GlobalOrNamespaceVariable src, Expr dest) {
not unreachable(dest) and
(
exists(GlobalOrNamespaceVariable v |
src = v and
dest = v.getAnAccess() and
not insideValueSource(dest)
)
or
exists(GlobalOrNamespaceVariable v, FieldAccess a |
unionAccess(v, _, a) and
src = v and
dest = a and
not insideValueSource(dest)
)
)
}
private predicate unionAccess(Variable v, Field f, FieldAccess a) {
f.getDeclaringType() instanceof Union and
a.getTarget() = f and
a.getQualifier() = v.getAnAccess()
}
deprecated GlobalOrNamespaceVariable globalVarFromId(string id) {
if result instanceof NamespaceVariable
then id = result.getNamespace() + "::" + result.getName()
else id = result.getName()
}
/**
* A variable that has any kind of upper-bound check anywhere in the program. This is
* biased towards being inclusive because there are a lot of valid ways of doing an
* upper bounds checks if we don't consider where it occurs, for example:
* ```
* if (x < 10) { sink(x); }
*
* if (10 > y) { sink(y); }
*
* if (z > 10) { z = 10; }
* sink(z);
* ```
*/
private predicate hasUpperBoundsCheck(Variable var) {
exists(RelationalOperation oper, VariableAccess access |
oper.getAnOperand() = access and
access.getTarget() = var and
// Comparing to 0 is not an upper bound check
not oper.getAnOperand().getValue() = "0"
)
}
cached
deprecated private predicate taintedWithArgsAndGlobalVars(
Element src, Element dest, boolean destFromArg, string globalVar
) {
isUserInput(src, _) and
not unreachable(src) and
dest = src and
destFromArg = false and
globalVar = ""
or
exists(Element other, boolean otherFromArg, string otherGlobalVar |
taintedWithArgsAndGlobalVars(src, other, otherFromArg, otherGlobalVar)
|
not unreachable(dest) and
not hasUpperBoundsCheck(dest) and
(
// Direct flow from one expression to another.
betweenFunctionsValueMoveTo(other, dest, destFromArg) and
(destFromArg = true or otherFromArg = false) and
globalVar = otherGlobalVar
or
insideFunctionValueMoveTo(other, dest) and
destFromArg = otherFromArg and
globalVar = otherGlobalVar
or
exists(GlobalOrNamespaceVariable v |
v = other and
globalVariableValueMoveTo(v, dest) and
destFromArg = false and
v = globalVarFromId(globalVar)
)
)
)
}
/**
* A tainted expression is either directly user input, or is
* computed from user input in a way that users can probably
* control the exact output of the computation.
*
* This doesn't include data flow through global variables.
* If you need that you must call taintedIncludingGlobalVars.
*/
deprecated predicate tainted(Expr source, Element tainted) {
taintedWithArgsAndGlobalVars(source, tainted, _, "")
}
/**
* A tainted expression is either directly user input, or is
* computed from user input in a way that users can probably
* control the exact output of the computation.
*
* This version gives the same results as tainted but also includes
* data flow through global variables.
*
* The parameter `globalVar` is the name of the last global variable used to move the
* value from source to tainted.
*/
deprecated predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) {
taintedWithArgsAndGlobalVars(source, tainted, _, globalVar)
}
/**
* A predictable expression is one where an external user can predict
* the value. For example, a literal in the source code is considered
* predictable.
*/
private predicate predictable(Expr expr) {
expr instanceof Literal
or
exists(BinaryOperation binop | binop = expr |
predictable(binop.getLeftOperand()) and predictable(binop.getRightOperand())
)
or
exists(UnaryOperation unop | unop = expr | predictable(unop.getOperand()))
}
private int maxArgIndex(Function f) {
result =
max(FunctionCall fc, int toMax |
fc.getTarget() = f and toMax = fc.getNumberOfArguments() - 1
|
toMax
)
}
/** Functions that copy the value of one argument to another */
private predicate copyValueBetweenArguments(Function f, int sourceArg, int destArg) {
f.hasGlobalOrStdName("memcpy") and sourceArg = 1 and destArg = 0
or
f.hasGlobalName("__builtin___memcpy_chk") and sourceArg = 1 and destArg = 0
or
f.hasGlobalOrStdName("memmove") and sourceArg = 1 and destArg = 0
or
f.hasGlobalOrStdName("strcat") and sourceArg = 1 and destArg = 0
or
f.hasGlobalName("_mbscat") and sourceArg = 1 and destArg = 0
or
f.hasGlobalOrStdName("wcscat") and sourceArg = 1 and destArg = 0
or
f.hasGlobalOrStdName("strncat") and sourceArg = 1 and destArg = 0
or
f.hasGlobalName("_mbsncat") and sourceArg = 1 and destArg = 0
or
f.hasGlobalName("wcsncat") and sourceArg = 1 and destArg = 0
or
f.hasGlobalOrStdName("strcpy") and sourceArg = 1 and destArg = 0
or
f.hasGlobalName("_mbscpy") and sourceArg = 1 and destArg = 0
or
f.hasGlobalOrStdName("wcscpy") and sourceArg = 1 and destArg = 0
or
f.hasGlobalOrStdName("strncpy") and sourceArg = 1 and destArg = 0
or
f.hasGlobalName("_mbsncpy") and sourceArg = 1 and destArg = 0
or
f.hasGlobalOrStdName("wcsncpy") and sourceArg = 1 and destArg = 0
or
f.hasGlobalName("inet_aton") and sourceArg = 0 and destArg = 1
or
f.hasGlobalName("inet_pton") and sourceArg = 1 and destArg = 2
or
f.hasGlobalOrStdName("strftime") and sourceArg in [2 .. maxArgIndex(f)] and destArg = 0
or
exists(FormattingFunction ff | ff = f |
sourceArg in [ff.getFormatParameterIndex() .. maxArgIndex(f)] and
destArg = ff.getOutputParameterIndex(false)
)
}
/** Functions where if one of the arguments is tainted, the result should be tainted */
private predicate returnArgument(Function f, int sourceArg) {
f.hasGlobalName("memcpy") and sourceArg = 0
or
f.hasGlobalName("__builtin___memcpy_chk") and sourceArg = 0
or
f.hasGlobalOrStdName("memmove") and sourceArg = 0
or
f.hasGlobalOrStdName("strcat") and sourceArg = 0
or
f.hasGlobalName("_mbscat") and sourceArg = 0
or
f.hasGlobalOrStdName("wcsncat") and sourceArg = 0
or
f.hasGlobalOrStdName("strncat") and sourceArg = 0
or
f.hasGlobalName("_mbsncat") and sourceArg = 0
or
f.hasGlobalOrStdName("wcsncat") and sourceArg = 0
or
f.hasGlobalOrStdName("strcpy") and sourceArg = 0
or
f.hasGlobalName("_mbscpy") and sourceArg = 0
or
f.hasGlobalOrStdName("wcscpy") and sourceArg = 0
or
f.hasGlobalOrStdName("strncpy") and sourceArg = 0
or
f.hasGlobalName("_mbsncpy") and sourceArg = 0
or
f.hasGlobalOrStdName("wcsncpy") and sourceArg = 0
or
f.hasGlobalName("inet_ntoa") and sourceArg = 0
or
f.hasGlobalName("inet_addr") and sourceArg = 0
or
f.hasGlobalName("inet_network") and sourceArg = 0
or
f.hasGlobalName("inet_ntoa") and sourceArg = 0
or
f.hasGlobalName("inet_makeaddr") and
(sourceArg = 0 or sourceArg = 1)
or
f.hasGlobalName("inet_lnaof") and sourceArg = 0
or
f.hasGlobalName("inet_netof") and sourceArg = 0
or
f.hasGlobalName("gethostbyname") and sourceArg = 0
or
f.hasGlobalName("gethostbyaddr") and sourceArg = 0
}
/**
* Resolve potential target function(s) for `call`.
*
* If `call` is a call through a function pointer (`ExprCall`) or
* targets a virtual method, simple data flow analysis is performed
* in order to identify target(s).
*/
deprecated Function resolveCall(Call call) {
result = call.getTarget()
or
result = call.(DataSensitiveCallExpr).resolve()
}
/** A data sensitive call expression. */
abstract deprecated library class DataSensitiveCallExpr extends Expr {
DataSensitiveCallExpr() { not unreachable(this) }
abstract Expr getSrc();
cached
abstract Function resolve();
/**
* Whether `src` can flow to this call expression.
*
* Searches backwards from `getSrc()` to `src`.
*/
predicate flowsFrom(Element src, boolean allowFromArg) {
src = this.getSrc() and allowFromArg = true
or
exists(Element other, boolean allowOtherFromArg | this.flowsFrom(other, allowOtherFromArg) |
exists(boolean otherFromArg | betweenFunctionsValueMoveToStatic(src, other, otherFromArg) |
otherFromArg = true and allowOtherFromArg = true and allowFromArg = true
or
otherFromArg = false and allowFromArg = false
)
or
insideFunctionValueMoveTo(src, other) and allowFromArg = allowOtherFromArg
or
globalVariableValueMoveTo(src, other) and allowFromArg = true
)
}
}
/** Call through a function pointer. */
deprecated library class DataSensitiveExprCall extends DataSensitiveCallExpr, ExprCall {
override Expr getSrc() { result = this.getExpr() }
override Function resolve() {
exists(FunctionAccess fa | this.flowsFrom(fa, true) | result = fa.getTarget())
}
}
/** Call to a virtual function. */
deprecated library class DataSensitiveOverriddenFunctionCall extends DataSensitiveCallExpr,
FunctionCall
{
DataSensitiveOverriddenFunctionCall() {
exists(this.getTarget().(VirtualFunction).getAnOverridingFunction())
}
override Expr getSrc() { result = this.getQualifier() }
override MemberFunction resolve() {
exists(NewExpr new |
this.flowsFrom(new, true) and
memberFunctionFromNewExpr(new, result) and
result.overrides*(this.getTarget().(VirtualFunction))
)
}
}
private predicate memberFunctionFromNewExpr(NewExpr new, MemberFunction f) {
f = new.getAllocatedType().(Class).getAMemberFunction()
}
/** Same as `betweenFunctionsValueMoveTo`, but calls are resolved to their static target. */
private predicate betweenFunctionsValueMoveToStatic(Element src, Element dest, boolean destFromArg) {
not unreachable(src) and
not unreachable(dest) and
(
exists(FunctionCall call, Function called, int i |
src = call.getArgument(i) and
called = call.getTarget() and
dest = called.getParameter(i) and
destFromArg = true
)
or
// Only move the return of the function to the function itself if the value didn't came from an
// argument, or else we would taint all the calls to one function if one argument is tainted
// somewhere
exists(Function f, ReturnStmt ret |
ret.getEnclosingFunction() = f and
src = ret.getExpr() and
destFromArg = false and
dest = f
)
or
exists(FunctionCall call, Function f |
call.getTarget() = f and
src = f and
dest = call and
destFromArg = false
)
or
// If a parameter of type reference is tainted inside a function, taint the argument too
exists(FunctionCall call, Function f, int pi, Parameter p |
call.getTarget() = f and
f.getParameter(pi) = p and
p.getType() instanceof ReferenceType and
src = p and
dest = call.getArgument(pi) and
destFromArg = false
)
)
}

View File

@@ -2149,7 +2149,7 @@ includes(
);
link_targets(
unique int id: @link_target,
int id: @link_target,
int binary: @file ref
);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Remove uniqueness constraint on link_targets/2
compatibility: full

View File

@@ -16,7 +16,11 @@ import semmle.code.cpp.dataflow.new.DataFlow
import FlowAfterFree
import DoubleFree::PathGraph
predicate isFree(DataFlow::Node n, Expr e) { isFree(n, e, _) }
/**
* Holds if `n` is a dataflow node that represents a pointer going into a
* deallocation function, and `e` is the corresponding expression.
*/
predicate isFree(DataFlow::Node n, Expr e) { isFree(_, n, e, _) }
/**
* `dealloc1` is a deallocation expression and `e` is an expression such
@@ -28,7 +32,7 @@ predicate isFree(DataFlow::Node n, Expr e) { isFree(n, e, _) }
*/
bindingset[dealloc1, e]
predicate isExcludeFreePair(DeallocationExpr dealloc1, Expr e) {
exists(DeallocationExpr dealloc2 | isFree(_, e, dealloc2) |
exists(DeallocationExpr dealloc2 | isFree(_, _, e, dealloc2) |
dealloc1.(FunctionCall).getTarget().hasGlobalName("MmFreePagesFromMdl") and
// From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
// "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
@@ -42,7 +46,7 @@ module DoubleFree = FlowFromFree<isFree/2, isExcludeFreePair/2>;
from DoubleFree::PathNode source, DoubleFree::PathNode sink, DeallocationExpr dealloc, Expr e2
where
DoubleFree::flowPath(source, sink) and
isFree(source.getNode(), _, dealloc) and
isFree(source.getNode(), _, _, dealloc) and
isFree(sink.getNode(), e2)
select sink.getNode(), source, sink,
"Memory pointed to by '" + e2.toString() + "' may already have been freed by $@.", dealloc,

View File

@@ -50,12 +50,12 @@ predicate strictlyDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
module FlowFromFreeConfig implements DataFlow::StateConfigSig {
class FlowState instanceof Expr {
FlowState() { isFree(_, this, _) }
FlowState() { isFree(_, _, this, _) }
string toString() { result = super.toString() }
}
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, state, _) }
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, _, state, _) }
pragma[inline]
predicate isSink(DataFlow::Node sink, FlowState state) {
@@ -64,7 +64,7 @@ module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
DeallocationExpr dealloc
|
isASink(sink, e) and
isFree(source, state, dealloc) and
isFree(source, _, state, dealloc) and
e != state and
source.hasIndexInBlock(b1, i1) and
sink.hasIndexInBlock(b2, i2) and
@@ -87,6 +87,8 @@ module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
|
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
)
or
n.asExpr() instanceof ArrayExpr
}
}
@@ -94,14 +96,17 @@ module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
}
/**
* Holds if `n` is a dataflow node such that `n.asExpr() = e` and `e`
* is being freed by a deallocation expression `dealloc`.
* Holds if `outgoing` is a dataflow node that represents the pointer passed to
* `dealloc` after the call returns (i.e., the post-update node associated with
* the argument to `dealloc`), and `incoming` is the corresponding argument
* node going into `dealloc` (i.e., the pre-update node of `outgoing`).
*/
predicate isFree(DataFlow::Node n, Expr e, DeallocationExpr dealloc) {
predicate isFree(DataFlow::Node outgoing, DataFlow::Node incoming, Expr e, DeallocationExpr dealloc) {
exists(Expr conv |
e = conv.getUnconverted() and
conv = dealloc.getFreedExpr().getFullyConverted() and
conv = n.asConvertedExpr()
incoming = outgoing.(DataFlow::PostUpdateNode).getPreUpdateNode() and
conv = incoming.asConvertedExpr()
) and
// Ignore realloc functions
not exists(dealloc.(FunctionCall).getTarget().(AllocationFunction).getReallocPtrArg())

View File

@@ -0,0 +1,30 @@
{
int i, j;
// BAD: The result is only checked against zero
if (scanf("%d %d", &i, &j)) {
use(i);
use(j);
}
// BAD: The result is only checked against zero
if (scanf("%d %d", &i, &j) == 0) {
i = 0;
j = 0;
}
use(i);
use(j);
if (scanf("%d %d", &i, &j) == 2) {
// GOOD: the result is checked against 2
}
// GOOD: the result is compared directly
int r = scanf("%d %d", &i, &j);
if (r < 2) {
return;
}
if (r == 1) {
j = 0;
}
}

View File

@@ -0,0 +1,37 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
This query finds calls of <tt>scanf</tt>-like functions with
improper return-value checking. Specifically, it flags uses of <code>scanf</code> where the return value is only checked against zero.
</p>
<p>
Functions in the <tt>scanf</tt> family return either <tt>EOF</tt> (a negative value)
in case of IO failure, or the number of items successfully read from the
input. Consequently, a simple check that the return value is nonzero
is not enough.
</p>
</overview>
<recommendation>
<p>
Ensure that all uses of <tt>scanf</tt> check the return value against the expected number of arguments
rather than just against zero.
</p>
</recommendation>
<example>
<p>The following examples show different ways of guarding a <tt>scanf</tt> output. In the BAD examples, the results are only checked against zero. In the GOOD examples, the results are checked against the expected number of matches instead.</p>
<sample src="IncorrectCheckScanf.cpp" />
</example>
<references>
<li>SEI CERT C++ Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/ERR62-CPP.+Detect+errors+when+converting+a+string+to+a+number">ERR62-CPP. Detect errors when converting a string to a number</a>.</li>
<li>SEI CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/ERR33-C.+Detect+and+handle+standard+library+errors">ERR33-C. Detect and handle standard library errors</a>.</li>
<li>cppreference.com: <a href="https://en.cppreference.com/w/c/io/fscanf">scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,21 @@
/**
* @name Incorrect return-value check for a 'scanf'-like function
* @description Failing to account for EOF in a call to a scanf-like function can lead to
* undefined behavior.
* @kind problem
* @problem.severity warning
* @security-severity 7.5
* @precision high
* @id cpp/incorrectly-checked-scanf
* @tags security
* correctness
* external/cwe/cwe-253
*/
import cpp
import semmle.code.cpp.commons.Scanf
import ScanfChecks
from ScanfFunctionCall call
where incorrectlyCheckedScanf(call)
select call, "The result of scanf is only checked against 0, but it can also return EOF."

View File

@@ -19,6 +19,7 @@ import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.dataflow.new.DataFlow::DataFlow
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.ValueNumbering
import ScanfChecks
/** Holds if `n` reaches an argument to a call to a `scanf`-like function. */
pragma[nomagic]
@@ -60,7 +61,9 @@ predicate isSink(ScanfFunctionCall call, int index, Node n, Expr input) {
* argument that has not been previously initialized.
*/
predicate isRelevantScanfCall(ScanfFunctionCall call, int index, Expr output) {
exists(Node n | fwdFlow0(n) and isSink(call, index, n, output))
exists(Node n | fwdFlow0(n) and isSink(call, index, n, output)) and
// Exclude results from incorrectky checked scanf query
not incorrectlyCheckedScanf(call)
}
/**

View File

@@ -0,0 +1,29 @@
private import cpp
private import semmle.code.cpp.commons.Scanf
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.ir.ValueNumbering
private predicate exprInBooleanContext(Expr e) {
exists(IRGuardCondition gc |
exists(Instruction i, ConstantInstruction zero |
zero.getValue() = "0" and
i.getUnconvertedResultExpression() = e and
gc.comparesEq(valueNumber(i).getAUse(), zero.getAUse(), 0, _, _)
)
or
gc.getUnconvertedResultExpression() = e
)
}
private predicate isLinuxKernel() {
// For the purpose of sscanf, we check the header guards for the files that it is defined in (which have changed)
exists(Macro macro | macro.getName() in ["_LINUX_KERNEL_SPRINTF_H_", "_LINUX_KERNEL_H"])
}
/**
* Holds if `call` is a `scanf`-like call were the result is only checked against 0, but it can also return EOF.
*/
predicate incorrectlyCheckedScanf(ScanfFunctionCall call) {
exprInBooleanContext(call) and
not isLinuxKernel() // scanf in the linux kernel can't return EOF
}

View File

@@ -30,7 +30,7 @@ private predicate externalCallNeverDereferences(FormattingFunctionCall call, int
}
predicate isUse0(Expr e) {
not isFree(_, e, _) and
not isFree(_, _, e, _) and
(
e = any(PointerDereferenceExpr pde).getOperand()
or
@@ -101,35 +101,43 @@ module ParameterSinks {
)
}
private CallInstruction getAnAlwaysReachedCallInstruction(IRFunction f) {
result.getBlock().postDominates(f.getEntryBlock())
private CallInstruction getAnAlwaysReachedCallInstruction() {
exists(IRFunction f | result.getBlock().postDominates(f.getEntryBlock()))
}
pragma[nomagic]
predicate callHasTargetAndArgument(Function f, int i, CallInstruction call, Instruction argument) {
call.getStaticCallTarget() = f and
call.getArgument(i) = argument
private predicate callHasTargetAndArgument(Function f, int i, Instruction argument) {
exists(CallInstruction call |
call.getStaticCallTarget() = f and
call.getArgument(i) = argument and
call = getAnAlwaysReachedCallInstruction()
)
}
pragma[nomagic]
predicate initializeParameterInFunction(Function f, int i, InitializeParameterInstruction init) {
pragma[only_bind_out](init.getEnclosingFunction()) = f and
init.hasIndex(i)
private predicate initializeParameterInFunction(Function f, int i) {
exists(InitializeParameterInstruction init |
pragma[only_bind_out](init.getEnclosingFunction()) = f and
init.hasIndex(i) and
init = getAnAlwaysDereferencedParameter()
)
}
pragma[nomagic]
private predicate alwaysDereferencedArgumentHasValueNumber(ValueNumber vn) {
exists(int i, Function f, Instruction argument |
callHasTargetAndArgument(f, i, argument) and
initializeParameterInFunction(pragma[only_bind_into](f), pragma[only_bind_into](i)) and
vn.getAnInstruction() = argument
)
}
InitializeParameterInstruction getAnAlwaysDereferencedParameter() {
result = getAnAlwaysDereferencedParameter0()
or
exists(
CallInstruction call, int i, InitializeParameterInstruction p, Instruction argument,
Function f
|
callHasTargetAndArgument(f, i, call, argument) and
initializeParameterInFunction(f, i, p) and
p = getAnAlwaysDereferencedParameter() and
result =
pragma[only_bind_out](pragma[only_bind_into](valueNumber(argument)).getAnInstruction()) and
call = getAnAlwaysReachedCallInstruction(_)
exists(ValueNumber vn |
alwaysDereferencedArgumentHasValueNumber(vn) and
vn.getAnInstruction() = result
)
}
}
@@ -170,6 +178,6 @@ module UseAfterFree = FlowFromFree<isUse/2, isExcludeFreeUsePair/2>;
from UseAfterFree::PathNode source, UseAfterFree::PathNode sink, DeallocationExpr dealloc
where
UseAfterFree::flowPath(source, sink) and
isFree(source.getNode(), _, dealloc)
isFree(source.getNode(), _, _, dealloc)
select sink.getNode(), source, sink, "Memory may have been previously freed by $@.", dealloc,
dealloc.toString()

View File

@@ -345,6 +345,8 @@ private module PossibleYearArithmeticOperationCheckConfig implements DataFlow::C
)
}
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
// flow from anything on the RHS of an assignment to a time/date structure to that
// assignment.

View File

@@ -24,7 +24,7 @@ import semmle.code.cpp.security.BufferWrite
from BufferWrite bw, int destSize
where
bw.hasExplicitLimit() and // has an explicit size limit
destSize = getBufferSize(bw.getDest(), _) and
destSize = max(getBufferSize(bw.getDest(), _)) and
bw.getExplicitLimit() > destSize // but it's larger than the destination
select bw,
"This '" + bw.getBWDesc() + "' operation is limited to " + bw.getExplicitLimit() +

View File

@@ -35,10 +35,10 @@ predicate isSource(FS::FlowSource source, string sourceType) { sourceType = sour
predicate isSink(DataFlow::Node sink, string kind) {
exists(Expr use |
use = sink.asExpr() and
not use.getUnspecifiedType() instanceof PointerType and
outOfBoundsExpr(use, kind) and
not inSystemMacroExpansion(use)
not inSystemMacroExpansion(use) and
use = sink.asExpr()
)
}

View File

@@ -0,0 +1,98 @@
import cpp
import semmle.code.cpp.models.implementations.StdContainer
/**
* Holds if `e` will be consumed by its parent as a glvalue and does not have
* an lvalue-to-rvalue conversion. This means that it will be materialized into
* a temporary object.
*/
predicate isTemporary(Expr e) {
e instanceof TemporaryObjectExpr
or
e.isPRValueCategory() and
e.getUnspecifiedType() instanceof Class and
not e.hasLValueToRValueConversion()
}
/** Holds if `e` is written to a container. */
predicate isStoredInContainer(Expr e) {
exists(StdSequenceContainerInsert insert, Call call, int index |
call = insert.getACallToThisFunction() and
index = insert.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceContainerPush push, Call call, int index |
call = push.getACallToThisFunction() and
index = push.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceEmplace emplace, Call call, int index |
call = emplace.getACallToThisFunction() and
index = emplace.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceEmplaceBack emplaceBack, Call call, int index |
call = emplaceBack.getACallToThisFunction() and
index = emplaceBack.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
}
/**
* Holds if `e` or a conversion of `e` has an lvalue-to-rvalue conversion.
*/
private predicate hasLValueToRValueConversion(Expr e) {
e.getConversion*().hasLValueToRValueConversion() and
not e instanceof ConditionalExpr // ConditionalExpr may be spuriously reported as having an lvalue-to-rvalue conversion
}
/**
* Holds if the value of `e` outlives the enclosing full expression. For
* example, because the value is stored in a local variable.
*/
predicate outlivesFullExpr(Expr e) {
not hasLValueToRValueConversion(e) and
(
any(Assignment assign).getRValue() = e
or
any(Variable v).getInitializer().getExpr() = e
or
any(ReturnStmt ret).getExpr() = e
or
exists(ConditionalExpr cond |
outlivesFullExpr(cond) and
[cond.getThen(), cond.getElse()] = e
)
or
exists(BinaryOperation bin |
outlivesFullExpr(bin) and
bin.getAnOperand() = e and
not bin instanceof ComparisonOperation
)
or
exists(PointerFieldAccess fa |
outlivesFullExpr(fa) and
fa.getQualifier() = e
)
or
exists(AddressOfExpr ao |
outlivesFullExpr(ao) and
ao.getOperand() = e
)
or
exists(ClassAggregateLiteral aggr |
outlivesFullExpr(aggr) and
aggr.getAFieldExpr(_) = e
)
or
exists(ArrayAggregateLiteral aggr |
outlivesFullExpr(aggr) and
aggr.getAnElementExpr(_) = e
)
or
isStoredInContainer(e)
)
}

View File

@@ -14,81 +14,7 @@
import cpp
import semmle.code.cpp.models.implementations.StdString
import semmle.code.cpp.models.implementations.StdContainer
/**
* Holds if `e` will be consumed by its parent as a glvalue and does not have
* an lvalue-to-rvalue conversion. This means that it will be materialized into
* a temporary object.
*/
predicate isTemporary(Expr e) {
e instanceof TemporaryObjectExpr
or
e.isPRValueCategory() and
e.getUnspecifiedType() instanceof Class and
not e.hasLValueToRValueConversion()
}
/** Holds if `e` is written to a container. */
predicate isStoredInContainer(Expr e) {
exists(StdSequenceContainerInsert insert, Call call, int index |
call = insert.getACallToThisFunction() and
index = insert.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceContainerPush push, Call call, int index |
call = push.getACallToThisFunction() and
index = push.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceEmplace emplace, Call call, int index |
call = emplace.getACallToThisFunction() and
index = emplace.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceEmplaceBack emplaceBack, Call call, int index |
call = emplaceBack.getACallToThisFunction() and
index = emplaceBack.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
}
/**
* Holds if the value of `e` outlives the enclosing full expression. For
* example, because the value is stored in a local variable.
*/
predicate outlivesFullExpr(Expr e) {
any(Assignment assign).getRValue() = e
or
any(Variable v).getInitializer().getExpr() = e
or
any(ReturnStmt ret).getExpr() = e
or
exists(ConditionalExpr cond |
outlivesFullExpr(cond) and
[cond.getThen(), cond.getElse()] = e
)
or
exists(BinaryOperation bin |
outlivesFullExpr(bin) and
bin.getAnOperand() = e
)
or
exists(ClassAggregateLiteral aggr |
outlivesFullExpr(aggr) and
aggr.getAFieldExpr(_) = e
)
or
exists(ArrayAggregateLiteral aggr |
outlivesFullExpr(aggr) and
aggr.getAnElementExpr(_) = e
)
or
isStoredInContainer(e)
}
import Temporaries
from Call c
where

View File

@@ -0,0 +1,44 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Calling <code>get</code> on a <code>std::unique_ptr</code> object returns a pointer to the underlying allocations.
When the <code>std::unique_ptr</code> object is destroyed, the pointer returned by <code>get</code> is no
longer valid. If the pointer is used after the <code>std::unique_ptr</code> object is destroyed, then the behavior is undefined.
</p>
</overview>
<recommendation>
<p>
Ensure that the pointer returned by <code>get</code> does not outlive the underlying <code>std::unique_ptr</code> object.
</p>
</recommendation>
<example>
<p>
The following example gets a <code>std::unique_ptr</code> object, and then converts the resulting unique pointer to a
pointer using <code>get</code> so that it can be passed to the <code>work</code> function.
However, the <code>std::unique_ptr</code> object is destroyed as soon as the call
to <code>get</code> returns. This means that <code>work</code> is given a pointer to invalid memory.
</p>
<sample src="UseOfUniquePointerAfterLifetimeEndsBad.cpp" />
<p>
The following example fixes the above code by ensuring that the pointer returned by the call to <code>get</code> does
not outlive the underlying <code>std::unique_ptr</code> objects. This ensures that the pointer passed to <code>work</code>
points to valid memory.
</p>
<sample src="UseOfUniquePointerAfterLifetimeEndsGood.cpp" />
</example>
<references>
<li><a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM50-CPP.+Do+not+access+freed+memory">MEM50-CPP. Do not access freed memory</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,36 @@
/**
* @name Use of unique pointer after lifetime ends
* @description Referencing the contents of a unique pointer after the underlying object has expired may lead to unexpected behavior.
* @kind problem
* @precision high
* @id cpp/use-of-unique-pointer-after-lifetime-ends
* @problem.severity warning
* @security-severity 8.8
* @tags reliability
* security
* external/cwe/cwe-416
* external/cwe/cwe-664
*/
import cpp
import semmle.code.cpp.models.interfaces.PointerWrapper
import Temporaries
predicate isUniquePointerDerefFunction(Function f) {
exists(PointerWrapper wrapper |
f = wrapper.getAnUnwrapperFunction() and
// We only want unique pointers as the memory behind share pointers may still be
// alive after the shared pointer is destroyed.
wrapper.(Class).hasQualifiedName(["std", "bsl"], "unique_ptr")
)
}
from Call c
where
outlivesFullExpr(c) and
not c.isFromUninstantiatedTemplate(_) and
isUniquePointerDerefFunction(c.getTarget()) and
isTemporary(c.getQualifier().getFullyConverted())
select c,
"The underlying unique pointer object is destroyed after the call to '" + c.getTarget() +
"' returns."

View File

@@ -0,0 +1,10 @@
#include <memory>
std::unique_ptr<T> getUniquePointer();
void work(const T*);
// BAD: the unique pointer is deallocated when `get` returns. So `work`
// is given a pointer to invalid memory.
void work_with_unique_ptr_bad() {
const T* combined_string = getUniquePointer().get();
work(combined_string);
}

View File

@@ -0,0 +1,10 @@
#include <memory>
std::unique_ptr<T> getUniquePointer();
void work(const T*);
// GOOD: the unique pointer outlives the call to `work`. So the pointer
// obtainted from `get` is valid.
void work_with_unique_ptr_good() {
auto combined_string = getUniquePointer();
work(combined_string.get());
}

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* The `cpp/incorrectly-checked-scanf` query has been added. This finds results where the return value of scanf is not checked correctly. Some of these were previously found by `cpp/missing-check-scanf` and will no longer be reported there.

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query, `cpp/use-of-unique-pointer-after-lifetime-ends`, to detect uses of the contents unique pointers that will be destroyed immediately.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `cpp/badly-bounded-write` query could report false positives when a pointer was first initialized with a literal and later assigned a dynamically allocated array. These false positives now no longer occur.

View File

@@ -0,0 +1,110 @@
/**
* @name Implementation of a cryptographic primitive
* @description Writing your own cryptographic primitives is prone to errors and omissions that weaken cryptographic protection.
* @kind problem
* @problem.severity warning
* @security-severity 7.5
* @precision medium
* @id cpp/crypto-primitive
* @tags security
* experimental
* external/cwe/cwe-1240
*/
import cpp
/**
* Gets a word that might be in the name of an encryption function.
*/
string encryptionWord() {
exists(string word |
// `(?<!P)` is negative lookbehind, i.e. the match is not preceded by `P`.
// `(?!P)` is negative lookahead, i.e. the match is not followed by `P`.
word =
[
"Crypt", "Cipher", "Aes", "Rijndael",
//"(?<!Wi|Co|No)Des(?!truct)",
"(?<!C)Rc[0-9]", "(?<!Cha|Unive)Rsa", "Blowfish", "Twofish", "Idea", "Kyber", "(?<!V)Aria",
//"Asn[0-9]",
"Camellia",
//"(?<!Bit|Type)Cast",
"Chacha", "ChaCha", "Poly[0-9]", "Ripemd", "Whirlpool", "Sbox", "SBox", "Cblock", "CBlock",
"Sub.?Bytes?", "Mix.?Columns?", "ECDH", "ECDSA", "EdDSA", "ECMQV", "ECQV", "Curve[0-9][0-9]"
] and
(
result = word or
result = word.toLowerCase() + "(?![a-z])" or // avoid matching middles of words
result = word.toUpperCase() + "(?![A-Z])" // avoid matching middles of words
)
)
}
/**
* Holds if `f` is a function whose name suggests it may be doing encryption
* (but may or may not actually implement an encryption primitive itself).
*/
predicate likelyEncryptionFunction(Function f) {
exists(string fName | fName = f.getName() |
fName.regexpMatch(".*(" + concat(encryptionWord(), "|") + ").*")
)
}
/**
* Holds if `t` is a type that is common in encryption-like computations. That
* is, an integral type or array of integral type elements.
*/
predicate computeHeuristicType(Type t) {
t instanceof IntegralType or
computeHeuristicType(t.(ArrayType).getBaseType().getUnspecifiedType())
}
/**
* Holds if `e` is an operation that is common in encryption-like computations.
* Looking for clusters of these tends to find things like encrpytion,
* compression, random number generation, graphics processing and other compute
* heavy algorithms.
*/
predicate computeHeuristic(Expr e) {
(
e instanceof BitwiseXorExpr or
e instanceof AssignXorExpr or
e instanceof LShiftExpr or
e instanceof AssignLShiftExpr or
e instanceof RShiftExpr or
e instanceof AssignRShiftExpr or
e instanceof ArrayExpr
) and
computeHeuristicType(e.getUnspecifiedType())
}
/**
* Gets the name of an established cryptography library or likely third party directory.
*/
string encryptionLibraryName() {
result =
[
"libssh", "openssl", "boringssl", "mbed", "libsodium", "libsrtp", "third.?party", "library",
"deps"
]
}
/**
* Holds if `f` is a file that is likely to be inside an established
* cryptography library.
*/
predicate isLibrary(File f) {
f.getAbsolutePath().regexpMatch("(?i).*(" + concat(encryptionLibraryName(), "|") + ").*")
or
// assume that any result that would be found outside the source location is in a crypto library
not exists(f.getFile().getRelativePath())
}
from Function f, int amount
where
likelyEncryptionFunction(f) and
amount = strictcount(Expr e | computeHeuristic(e) and e.getEnclosingFunction() = f) and
amount >= 8 and
not isLibrary(f.getFile())
select f,
"This function, \"" + f.getName() +
"\", may be a custom implementation of a cryptographic primitive."

View File

@@ -126,13 +126,13 @@ class Resource extends MemberVariable {
}
private predicate calledFromDestructor(Function f) {
f instanceof Destructor and f.getDeclaringType() = this.getDeclaringType()
pragma[only_bind_into](f) instanceof Destructor and
f.getDeclaringType() = this.getDeclaringType()
or
exists(Function mid, FunctionCall fc |
exists(Function mid |
this.calledFromDestructor(mid) and
fc.getEnclosingFunction() = mid and
fc.getTarget() = f and
f.getDeclaringType() = this.getDeclaringType()
mid.calls(f) and
pragma[only_bind_out](f.getDeclaringType()) = pragma[only_bind_out](this.getDeclaringType())
)
}

View File

@@ -32,18 +32,41 @@ predicate hasReferenceInitializer(EnumConstant c) {
)
}
/**
* Gets the `rnk`'th (1-based) enumeration constant in `e` that does not have a
* reference initializer (i.e., an initializer that refers to an enumeration
* constant from the same enumeration).
*/
EnumConstant getNonReferenceInitializedEnumConstantByRank(Enum e, int rnk) {
result =
rank[rnk](EnumConstant cand, int pos, string filepath, int startline, int startcolumn |
e.getEnumConstant(pos) = cand and
not hasReferenceInitializer(cand) and
cand.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _)
|
cand order by pos, filepath, startline, startcolumn
)
}
/**
* Holds if `ec` is not the last enumeration constant in `e` that has a non-
* reference initializer.
*/
predicate hasNextWithoutReferenceInitializer(Enum e, EnumConstant ec) {
exists(int rnk |
ec = getNonReferenceInitializedEnumConstantByRank(e, rnk) and
exists(getNonReferenceInitializedEnumConstantByRank(e, rnk + 1))
)
}
// There exists another constant whose value is implicit, but it's
// not the last one: the last value is okay to use to get the highest
// enum value automatically. It can be followed by aliases though.
predicate enumThatHasConstantWithImplicitValue(Enum e) {
exists(EnumConstant ec, int pos |
ec = e.getEnumConstant(pos) and
exists(EnumConstant ec |
ec = e.getAnEnumConstant() and
not hasInitializer(ec) and
exists(EnumConstant ec2, int pos2 |
ec2 = e.getEnumConstant(pos2) and
pos2 > pos and
not hasReferenceInitializer(ec2)
)
hasNextWithoutReferenceInitializer(e, ec)
)
}

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.9.0
version: 0.9.1-dev
groups:
- cpp
- queries

View File

@@ -1,8 +1,8 @@
edges
| test.cpp:22:27:22:30 | argv indirection | test.cpp:29:13:29:20 | filePath indirection |
| test.cpp:22:27:22:30 | **argv | test.cpp:29:13:29:20 | *filePath |
nodes
| test.cpp:22:27:22:30 | argv indirection | semmle.label | argv indirection |
| test.cpp:29:13:29:20 | filePath indirection | semmle.label | filePath indirection |
| test.cpp:22:27:22:30 | **argv | semmle.label | **argv |
| test.cpp:29:13:29:20 | *filePath | semmle.label | *filePath |
subpaths
#select
| test.cpp:29:13:29:20 | filePath indirection | test.cpp:22:27:22:30 | argv indirection | test.cpp:29:13:29:20 | filePath indirection | Using user-supplied data in a `wordexp` command, without disabling command substitution, can make code vulnerable to command injection. |
| test.cpp:29:13:29:20 | *filePath | test.cpp:22:27:22:30 | **argv | test.cpp:29:13:29:20 | *filePath | Using user-supplied data in a `wordexp` command, without disabling command substitution, can make code vulnerable to command injection. |

View File

@@ -0,0 +1,4 @@
| tests_crypto.cpp:11:6:11:18 | encryptString | This function, "encryptString", may be a custom implementation of a cryptographic primitive. |
| tests_crypto.cpp:30:6:30:14 | MyEncrypt | This function, "MyEncrypt", may be a custom implementation of a cryptographic primitive. |
| tests_crypto.cpp:51:6:51:16 | mix_columns | This function, "mix_columns", may be a custom implementation of a cryptographic primitive. |
| tests_crypto.cpp:83:6:83:18 | init_aes_sbox | This function, "init_aes_sbox", may be a custom implementation of a cryptographic primitive. |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-1240/CustomCryptographicPrimitive.ql

View File

@@ -0,0 +1,6 @@
// Cryptography 'library' snippets. Nothing in this file should be flagged by the query, because
// it's in a library.
void do_aes_encrypt(unsigned int *v) {
COMPUTE(v)
}

View File

@@ -0,0 +1,97 @@
// Cryptography snippets. All (non-stub) functions in this file should be flagged by the query.
typedef unsigned char uint8_t;
int strlen(const char *string);
// ---
// the following function is homebrew crypto written for this test. This is a bad algorithm
// on multiple levels and should never be used in cryptography.
void encryptString(char *string, unsigned int key) {
char *ptr = string;
int len = strlen(string);
while (len >= 4) {
// encrypt block by XOR-ing with the key
ptr[0] = ptr[0] ^ (key >> 0);
ptr[1] = ptr[1] ^ (key >> 8);
ptr[2] = ptr[2] ^ (key >> 16);
ptr[3] = ptr[3] ^ (key >> 24);
// move on
ptr += 4;
len -= 4;
}
}
// the following function is homebrew crypto written for this test. This is a bad algorithm
// on multiple levels and should never be used in cryptography.
void MyEncrypt(const unsigned int *dataIn, unsigned int *dataOut, unsigned int dataSize, unsigned int key[2]) {
unsigned int state[2];
unsigned int t;
state[0] = key[0];
state[1] = key[1];
for (unsigned int i = 0; i < dataSize; i++) {
// mix state
t = state[0];
state[0] = (state[0] << 1) | (state[1] >> 31);
state[1] = (state[1] << 1) | (t >> 31);
// encrypt data
dataOut[i] = dataIn[i] ^ state[0];
}
}
// the following function resembles an implementation of the AES "mix columns"
// step. It is not accurate, efficient or safe and should never be used in
// cryptography.
void mix_columns(const uint8_t inputs[4], uint8_t outputs[4]) {
// The "mix columns" step takes four bytes as inputs. Each byte represents a
// polynomial with 8 one-bit coefficients, e.g. input bits 00001101
// represent the polynomial x^3 + x^2 + 1. Arithmetic is reduced modulo
// x^8 + x^4 + x^3 + x + 1 (= 0x11b).
//
// The "mix columns" step multiplies each input by 2 (in the field described
// above) to produce four more values. The output is then four values
// produced by XOR-ing specific combinations of five of these eight values.
// The exact values selected here do not match the actual AES algorithm.
//
// We avoid control flow decisions that depend on the inputs.
uint8_t vs[4];
vs[0] = inputs[0] << 1; // multiply by two
vs[0] ^= (inputs[0] >> 7) * 0x1b; // reduce modulo 0x11b; the top bit was removed in the shift.
vs[1] = inputs[1] << 1;
vs[1] ^= (inputs[1] >> 7) * 0x1b;
vs[2] = inputs[2] << 1;
vs[2] ^= (inputs[2] >> 7) * 0x1b;
vs[3] = inputs[3] << 1;
vs[3] ^= (inputs[3] >> 7) * 0x1b;
outputs[0] = inputs[0] ^ inputs[1] ^ inputs[2] ^ vs[0] ^ vs[1];
outputs[1] = inputs[1] ^ inputs[2] ^ inputs[3] ^ vs[1] ^ vs[2];
outputs[2] = inputs[2] ^ inputs[3] ^ inputs[0] ^ vs[2] ^ vs[3];
outputs[3] = inputs[3] ^ inputs[0] ^ inputs[1] ^ vs[3] ^ vs[0];
}
// the following function resembles initialization of an S-box as may be done
// in an implementation of DES, AES and other encryption algorithms. It is not
// accurate, efficient or safe and should never be used in cryptography.
void init_aes_sbox(unsigned char data[256]) {
// initialize `data` in a loop using lots of ^, ^= and << operations and
// a few fixed constants.
unsigned int state = 0x12345678;
for (int i = 0; i < 256; i++)
{
state ^= (i ^ 0x86) << 24;
state ^= (i ^ 0xb9) << 16;
state ^= (i ^ 0x11) << 8;
state ^= (i ^ 0x23) << 0;
state = (state << 1) ^ (state >> 31);
data[i] = state & 0xff;
}
}

View File

@@ -0,0 +1,138 @@
// Non-cryptography snippets. Nothing in this file should be flagged by the query.
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned long size_t;
// a very cut down stub for `std::cout`
namespace std
{
template<class charT> struct char_traits;
template <class charT, class traits = char_traits<charT> >
class basic_ostream {
public:
typedef charT char_type;
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
typedef basic_ostream<char> ostream;
extern ostream cout;
}
// this macro expands to some compute operations that look a bit like cryptography
#define COMPUTE(v) \
v[0] ^= v[1] ^ v[2] ^ v[3] ^ v[4]; \
v[1] ^= v[2] ^ v[3] ^ v[4] ^ v[5]; \
v[2] ^= v[3] ^ v[4] ^ v[5] ^ v[6]; \
v[3] ^= v[4] ^ v[5] ^ v[6] ^ v[7];
// ---
#include "library/tests_library.h"
bool isEnabledAes() {
// This function has "Aes" in it's name, but does not contain enough compute to
// be an encryption implementation.
return false;
}
uint32_t lookup[256];
uint8_t computeCRC32(const uint8_t *data, size_t dataLen) {
// This function has "RC3" in its name, but is not an implementation of the (broken) RC3 encryption algorithm.
uint32_t result = 0xFFFFFFFF;
for (size_t i = 0; i < dataLen; i++) {
result = (result >> 8) + lookup[(result ^ data[i]) & 0xFF];
result = (result >> 8) + lookup[(result ^ data[i]) & 0xFF]; // artificial extra compute
result = (result >> 8) + lookup[(result ^ data[i]) & 0xFF]; // artificial extra compute
result = (result >> 8) + lookup[(result ^ data[i]) & 0xFF]; // artificial extra compute
}
return result ^ 0xFFFFFFFF;
}
void convert_image_universal(uint32_t *img, int width, int height) {
// This function has "rsa" in its name, but is nothing to do with the RSA encryption algorithm.
uint32_t *pixel_ptr = img;
uint32_t num_pixels = width * height;
// convert pixels RGBA -> ARGB (with probably unhelpful loop unrolling)
while (num_pixels >= 4) {
pixel_ptr[0] = (pixel_ptr[0] >> 8) ^ (pixel_ptr[0] << 24);
pixel_ptr[1] = (pixel_ptr[1] >> 8) ^ (pixel_ptr[1] << 24);
pixel_ptr[2] = (pixel_ptr[2] >> 8) ^ (pixel_ptr[2] << 24);
pixel_ptr[3] = (pixel_ptr[3] >> 8) ^ (pixel_ptr[3] << 24);
num_pixels -= 4;
}
if (num_pixels >= 2) {
pixel_ptr[0] = (pixel_ptr[0] >> 8) ^ (pixel_ptr[0] << 24);
pixel_ptr[1] = (pixel_ptr[1] >> 8) ^ (pixel_ptr[1] << 24);
num_pixels -= 2;
}
if (num_pixels >= 1) {
pixel_ptr[2] = (pixel_ptr[2] >> 8) ^ (pixel_ptr[2] << 24);
}
}
const char* yes_no_setting() { return "no"; }
void output_encrypt_decrypt_algorithms() {
// This function has "encrypt" and "decrypt" in its name, but no encryption is done.
// This function uses `<<` heavily, but not as an integer shift left.
const char *indent = " ";
std::cout << "Supported algorithms:\n";
std::cout << indent << "DES (" << yes_no_setting() << ")\n";
std::cout << indent << "3DES (" << yes_no_setting() << ")\n";
std::cout << indent << "AES (" << yes_no_setting() << ")\n";
std::cout << indent << "RSA (" << yes_no_setting() << ")\n";
std::cout << indent << "Blowfish (" << yes_no_setting() << ")\n";
std::cout << indent << "Twofish (" << yes_no_setting() << ")\n";
std::cout << indent << "Chacha (" << yes_no_setting() << ")\n";
}
void wideStringCharsAt(int *v) {
// This function has "des" and "rsa" in the name.
COMPUTE(v)
}
void bitcastVariable(int *v) {
// This function has "aria" and "cast" in the name.
COMPUTE(v)
}
void dividesVariance(int *v) {
// This function has "des" and "aria" in the name.
COMPUTE(v)
}
void broadcastNodes(int *v) {
// This function has "cast" and "des" in the name.
COMPUTE(v)
}
#define ROTATE(val, amount) ( (val << amount) | (val >> (32 - amount)) )
static inline void hashMix(const int *data, int &state) {
// This function looks like part of a hashing function. It's not necessarily intended to
// be a cryptographic hash, so should not be flagged.
state ^= data[0];
ROTATE(state, 1);
state ^= data[1];
ROTATE(state, 7);
state ^= data[2];
ROTATE(state, 11);
state ^= data[3];
ROTATE(state, 3);
state ^= data[4];
ROTATE(state, 13);
state ^= data[5];
ROTATE(state, 5);
state ^= data[6];
ROTATE(state, 2);
state ^= data[7];
ROTATE(state, 17);
}

View File

@@ -1,87 +1,87 @@
edges
| test.cpp:4:17:4:22 | call to malloc | test.cpp:6:9:6:11 | arr |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:10:9:10:11 | arr |
| test.cpp:19:9:19:16 | mk_array indirection [p] | test.cpp:28:19:28:26 | call to mk_array [p] |
| test.cpp:19:9:19:16 | mk_array indirection [p] | test.cpp:50:18:50:25 | call to mk_array [p] |
| test.cpp:21:5:21:24 | ... = ... | test.cpp:21:9:21:9 | arr indirection [post update] [p] |
| test.cpp:21:9:21:9 | arr indirection [post update] [p] | test.cpp:22:5:22:7 | arr indirection [p] |
| test.cpp:19:9:19:16 | *mk_array [p] | test.cpp:28:19:28:26 | call to mk_array [p] |
| test.cpp:19:9:19:16 | *mk_array [p] | test.cpp:50:18:50:25 | call to mk_array [p] |
| test.cpp:21:5:21:7 | *arr [post update] [p] | test.cpp:22:5:22:7 | *arr [p] |
| test.cpp:21:5:21:24 | ... = ... | test.cpp:21:5:21:7 | *arr [post update] [p] |
| test.cpp:21:13:21:18 | call to malloc | test.cpp:21:5:21:24 | ... = ... |
| test.cpp:22:5:22:7 | arr indirection [p] | test.cpp:19:9:19:16 | mk_array indirection [p] |
| test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:31:9:31:11 | arr indirection [p] |
| test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:35:9:35:11 | arr indirection [p] |
| test.cpp:31:9:31:11 | arr indirection [p] | test.cpp:31:13:31:13 | p |
| test.cpp:35:9:35:11 | arr indirection [p] | test.cpp:35:13:35:13 | p |
| test.cpp:39:27:39:29 | arr [p] | test.cpp:41:9:41:11 | arr indirection [p] |
| test.cpp:39:27:39:29 | arr [p] | test.cpp:45:9:45:11 | arr indirection [p] |
| test.cpp:41:9:41:11 | arr indirection [p] | test.cpp:41:13:41:13 | p |
| test.cpp:45:9:45:11 | arr indirection [p] | test.cpp:45:13:45:13 | p |
| test.cpp:22:5:22:7 | *arr [p] | test.cpp:19:9:19:16 | *mk_array [p] |
| test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:31:9:31:11 | *arr [p] |
| test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:35:9:35:11 | *arr [p] |
| test.cpp:31:9:31:11 | *arr [p] | test.cpp:31:13:31:13 | p |
| test.cpp:35:9:35:11 | *arr [p] | test.cpp:35:13:35:13 | p |
| test.cpp:39:27:39:29 | arr [p] | test.cpp:41:9:41:11 | *arr [p] |
| test.cpp:39:27:39:29 | arr [p] | test.cpp:45:9:45:11 | *arr [p] |
| test.cpp:41:9:41:11 | *arr [p] | test.cpp:41:13:41:13 | p |
| test.cpp:45:9:45:11 | *arr [p] | test.cpp:45:13:45:13 | p |
| test.cpp:50:18:50:25 | call to mk_array [p] | test.cpp:39:27:39:29 | arr [p] |
| test.cpp:55:5:55:24 | ... = ... | test.cpp:55:9:55:9 | arr indirection [post update] [p] |
| test.cpp:55:9:55:9 | arr indirection [post update] [p] | test.cpp:56:5:56:7 | arr indirection [p] |
| test.cpp:55:5:55:7 | *arr [post update] [p] | test.cpp:56:5:56:7 | *arr [p] |
| test.cpp:55:5:55:24 | ... = ... | test.cpp:55:5:55:7 | *arr [post update] [p] |
| test.cpp:55:13:55:18 | call to malloc | test.cpp:55:5:55:24 | ... = ... |
| test.cpp:56:5:56:7 | arr indirection [p] | test.cpp:59:9:59:11 | arr indirection [p] |
| test.cpp:56:5:56:7 | arr indirection [p] | test.cpp:63:9:63:11 | arr indirection [p] |
| test.cpp:59:9:59:11 | arr indirection [p] | test.cpp:59:13:59:13 | p |
| test.cpp:63:9:63:11 | arr indirection [p] | test.cpp:63:13:63:13 | p |
| test.cpp:67:10:67:19 | mk_array_p indirection [p] | test.cpp:76:20:76:29 | call to mk_array_p indirection [p] |
| test.cpp:67:10:67:19 | mk_array_p indirection [p] | test.cpp:98:18:98:27 | call to mk_array_p indirection [p] |
| test.cpp:69:5:69:25 | ... = ... | test.cpp:69:10:69:10 | arr indirection [post update] [p] |
| test.cpp:69:10:69:10 | arr indirection [post update] [p] | test.cpp:70:5:70:7 | arr indirection [p] |
| test.cpp:56:5:56:7 | *arr [p] | test.cpp:59:9:59:11 | *arr [p] |
| test.cpp:56:5:56:7 | *arr [p] | test.cpp:63:9:63:11 | *arr [p] |
| test.cpp:59:9:59:11 | *arr [p] | test.cpp:59:13:59:13 | p |
| test.cpp:63:9:63:11 | *arr [p] | test.cpp:63:13:63:13 | p |
| test.cpp:67:10:67:19 | **mk_array_p [p] | test.cpp:76:20:76:29 | *call to mk_array_p [p] |
| test.cpp:67:10:67:19 | **mk_array_p [p] | test.cpp:98:18:98:27 | *call to mk_array_p [p] |
| test.cpp:69:5:69:7 | *arr [post update] [p] | test.cpp:70:5:70:7 | *arr [p] |
| test.cpp:69:5:69:25 | ... = ... | test.cpp:69:5:69:7 | *arr [post update] [p] |
| test.cpp:69:14:69:19 | call to malloc | test.cpp:69:5:69:25 | ... = ... |
| test.cpp:70:5:70:7 | arr indirection [p] | test.cpp:67:10:67:19 | mk_array_p indirection [p] |
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:79:9:79:11 | arr indirection [p] |
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:83:9:83:11 | arr indirection [p] |
| test.cpp:79:9:79:11 | arr indirection [p] | test.cpp:79:14:79:14 | p |
| test.cpp:83:9:83:11 | arr indirection [p] | test.cpp:83:14:83:14 | p |
| test.cpp:87:28:87:30 | arr indirection [p] | test.cpp:89:9:89:11 | arr indirection [p] |
| test.cpp:87:28:87:30 | arr indirection [p] | test.cpp:93:9:93:11 | arr indirection [p] |
| test.cpp:89:9:89:11 | arr indirection [p] | test.cpp:89:14:89:14 | p |
| test.cpp:93:9:93:11 | arr indirection [p] | test.cpp:93:14:93:14 | p |
| test.cpp:98:18:98:27 | call to mk_array_p indirection [p] | test.cpp:87:28:87:30 | arr indirection [p] |
| test.cpp:70:5:70:7 | *arr [p] | test.cpp:67:10:67:19 | **mk_array_p [p] |
| test.cpp:76:20:76:29 | *call to mk_array_p [p] | test.cpp:79:9:79:11 | *arr [p] |
| test.cpp:76:20:76:29 | *call to mk_array_p [p] | test.cpp:83:9:83:11 | *arr [p] |
| test.cpp:79:9:79:11 | *arr [p] | test.cpp:79:14:79:14 | p |
| test.cpp:83:9:83:11 | *arr [p] | test.cpp:83:14:83:14 | p |
| test.cpp:87:28:87:30 | *arr [p] | test.cpp:89:9:89:11 | *arr [p] |
| test.cpp:87:28:87:30 | *arr [p] | test.cpp:93:9:93:11 | *arr [p] |
| test.cpp:89:9:89:11 | *arr [p] | test.cpp:89:14:89:14 | p |
| test.cpp:93:9:93:11 | *arr [p] | test.cpp:93:14:93:14 | p |
| test.cpp:98:18:98:27 | *call to mk_array_p [p] | test.cpp:87:28:87:30 | *arr [p] |
nodes
| test.cpp:4:17:4:22 | call to malloc | semmle.label | call to malloc |
| test.cpp:6:9:6:11 | arr | semmle.label | arr |
| test.cpp:10:9:10:11 | arr | semmle.label | arr |
| test.cpp:19:9:19:16 | mk_array indirection [p] | semmle.label | mk_array indirection [p] |
| test.cpp:19:9:19:16 | *mk_array [p] | semmle.label | *mk_array [p] |
| test.cpp:21:5:21:7 | *arr [post update] [p] | semmle.label | *arr [post update] [p] |
| test.cpp:21:5:21:24 | ... = ... | semmle.label | ... = ... |
| test.cpp:21:9:21:9 | arr indirection [post update] [p] | semmle.label | arr indirection [post update] [p] |
| test.cpp:21:13:21:18 | call to malloc | semmle.label | call to malloc |
| test.cpp:22:5:22:7 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:22:5:22:7 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:28:19:28:26 | call to mk_array [p] | semmle.label | call to mk_array [p] |
| test.cpp:31:9:31:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:31:9:31:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:31:13:31:13 | p | semmle.label | p |
| test.cpp:35:9:35:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:35:9:35:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:35:13:35:13 | p | semmle.label | p |
| test.cpp:39:27:39:29 | arr [p] | semmle.label | arr [p] |
| test.cpp:41:9:41:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:41:9:41:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:41:13:41:13 | p | semmle.label | p |
| test.cpp:45:9:45:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:45:9:45:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:45:13:45:13 | p | semmle.label | p |
| test.cpp:50:18:50:25 | call to mk_array [p] | semmle.label | call to mk_array [p] |
| test.cpp:55:5:55:7 | *arr [post update] [p] | semmle.label | *arr [post update] [p] |
| test.cpp:55:5:55:24 | ... = ... | semmle.label | ... = ... |
| test.cpp:55:9:55:9 | arr indirection [post update] [p] | semmle.label | arr indirection [post update] [p] |
| test.cpp:55:13:55:18 | call to malloc | semmle.label | call to malloc |
| test.cpp:56:5:56:7 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:59:9:59:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:56:5:56:7 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:59:9:59:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:59:13:59:13 | p | semmle.label | p |
| test.cpp:63:9:63:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:63:9:63:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:63:13:63:13 | p | semmle.label | p |
| test.cpp:67:10:67:19 | mk_array_p indirection [p] | semmle.label | mk_array_p indirection [p] |
| test.cpp:67:10:67:19 | **mk_array_p [p] | semmle.label | **mk_array_p [p] |
| test.cpp:69:5:69:7 | *arr [post update] [p] | semmle.label | *arr [post update] [p] |
| test.cpp:69:5:69:25 | ... = ... | semmle.label | ... = ... |
| test.cpp:69:10:69:10 | arr indirection [post update] [p] | semmle.label | arr indirection [post update] [p] |
| test.cpp:69:14:69:19 | call to malloc | semmle.label | call to malloc |
| test.cpp:70:5:70:7 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | semmle.label | call to mk_array_p indirection [p] |
| test.cpp:79:9:79:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:70:5:70:7 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:76:20:76:29 | *call to mk_array_p [p] | semmle.label | *call to mk_array_p [p] |
| test.cpp:79:9:79:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:79:14:79:14 | p | semmle.label | p |
| test.cpp:83:9:83:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:83:9:83:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:83:14:83:14 | p | semmle.label | p |
| test.cpp:87:28:87:30 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:89:9:89:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:87:28:87:30 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:89:9:89:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:89:14:89:14 | p | semmle.label | p |
| test.cpp:93:9:93:11 | arr indirection [p] | semmle.label | arr indirection [p] |
| test.cpp:93:9:93:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:93:14:93:14 | p | semmle.label | p |
| test.cpp:98:18:98:27 | call to mk_array_p indirection [p] | semmle.label | call to mk_array_p indirection [p] |
| test.cpp:98:18:98:27 | *call to mk_array_p [p] | semmle.label | *call to mk_array_p [p] |
subpaths
#select
| test.cpp:10:9:10:11 | arr | test.cpp:4:17:4:22 | call to malloc | test.cpp:10:9:10:11 | arr | Off-by one error allocated at $@ bounded by $@. | test.cpp:4:17:4:22 | call to malloc | call to malloc | test.cpp:4:24:4:27 | size | size |

View File

@@ -35,10 +35,10 @@ edges
| test.cpp:136:9:136:16 | ... += ... | test.cpp:138:13:138:15 | arr |
| test.cpp:143:18:143:21 | asdf | test.cpp:134:25:134:27 | arr |
| test.cpp:143:18:143:21 | asdf | test.cpp:143:18:143:21 | asdf |
| test.cpp:146:26:146:26 | p indirection | test.cpp:147:4:147:9 | -- ... |
| test.cpp:146:26:146:26 | *p | test.cpp:147:4:147:9 | -- ... |
| test.cpp:156:12:156:14 | buf | test.cpp:156:12:156:18 | ... + ... |
| test.cpp:156:12:156:18 | ... + ... | test.cpp:158:17:158:18 | & ... indirection |
| test.cpp:158:17:158:18 | & ... indirection | test.cpp:146:26:146:26 | p indirection |
| test.cpp:156:12:156:18 | ... + ... | test.cpp:158:17:158:18 | *& ... |
| test.cpp:158:17:158:18 | *& ... | test.cpp:146:26:146:26 | *p |
| test.cpp:218:23:218:28 | buffer | test.cpp:220:5:220:11 | access to array |
| test.cpp:218:23:218:28 | buffer | test.cpp:221:5:221:11 | access to array |
| test.cpp:229:25:229:29 | array | test.cpp:231:5:231:10 | access to array |
@@ -121,11 +121,11 @@ nodes
| test.cpp:138:13:138:15 | arr | semmle.label | arr |
| test.cpp:143:18:143:21 | asdf | semmle.label | asdf |
| test.cpp:143:18:143:21 | asdf | semmle.label | asdf |
| test.cpp:146:26:146:26 | p indirection | semmle.label | p indirection |
| test.cpp:146:26:146:26 | *p | semmle.label | *p |
| test.cpp:147:4:147:9 | -- ... | semmle.label | -- ... |
| test.cpp:156:12:156:14 | buf | semmle.label | buf |
| test.cpp:156:12:156:18 | ... + ... | semmle.label | ... + ... |
| test.cpp:158:17:158:18 | & ... indirection | semmle.label | & ... indirection |
| test.cpp:158:17:158:18 | *& ... | semmle.label | *& ... |
| test.cpp:218:23:218:28 | buffer | semmle.label | buffer |
| test.cpp:220:5:220:11 | access to array | semmle.label | access to array |
| test.cpp:221:5:221:11 | access to array | semmle.label | access to array |

View File

@@ -1,5 +1,5 @@
edges
| test.cpp:45:18:45:23 | buffer | test.cpp:45:7:45:10 | func indirection |
| test.cpp:45:18:45:23 | buffer | test.cpp:45:7:45:10 | *func |
| test.cpp:74:24:74:30 | medical | test.cpp:78:24:78:27 | temp |
| test.cpp:74:24:74:30 | medical | test.cpp:81:22:81:28 | medical |
| test.cpp:77:16:77:22 | medical | test.cpp:78:24:78:27 | temp |
@@ -10,7 +10,7 @@ edges
| test.cpp:96:37:96:46 | theZipcode | test.cpp:99:42:99:51 | theZipcode |
| test.cpp:99:61:99:70 | theZipcode | test.cpp:99:42:99:51 | theZipcode |
nodes
| test.cpp:45:7:45:10 | func indirection | semmle.label | func indirection |
| test.cpp:45:7:45:10 | *func | semmle.label | *func |
| test.cpp:45:18:45:23 | buffer | semmle.label | buffer |
| test.cpp:57:9:57:18 | theZipcode | semmle.label | theZipcode |
| test.cpp:74:24:74:30 | medical | semmle.label | medical |
@@ -25,7 +25,7 @@ nodes
| test.cpp:99:42:99:51 | theZipcode | semmle.label | theZipcode |
| test.cpp:99:61:99:70 | theZipcode | semmle.label | theZipcode |
subpaths
| test.cpp:81:22:81:28 | medical | test.cpp:45:18:45:23 | buffer | test.cpp:45:7:45:10 | func indirection | test.cpp:81:17:81:20 | call to func |
| test.cpp:81:22:81:28 | medical | test.cpp:45:18:45:23 | buffer | test.cpp:45:7:45:10 | *func | test.cpp:81:17:81:20 | call to func |
#select
| test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | 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 of private data. |
| test.cpp:74:24:74:30 | medical | test.cpp:74:24:74:30 | medical | 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 of private data. |

View File

@@ -1,6 +1,7 @@
| b.c:5:3:5:34 | return ... | 10 |
| c.c:2:3:2:20 | return ... | 5 |
| e.c:2:3:2:19 | return ... | 17 |
| g.c:3:3:3:12 | return ... | 20 |
| i.c:3:3:3:12 | return ... | 30 |
| i.c:8:3:8:12 | return ... | 31 |
| i.c:13:3:13:12 | return ... | 32 |

View File

@@ -3,4 +3,4 @@ static int g() {
return 20;
}
#endif
// semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/f.pch --expect_errors
// semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/f.pch

View File

@@ -1,6 +1,6 @@
#ifdef SEEN_H
static int h() {
return 30; // [FALSE POSITIVE] (#pragma hdrstop bug, SEEN_H should not be defined in the precompiled header)
return 30;
}
#endif
#ifdef H1
@@ -10,7 +10,7 @@ static int h1() {
#endif
#ifdef H2
static int h2() {
return 32; // [FALSE POSITIVE] (#pragma hdrstop bug, H2 should not be defined in the precompiled header)
return 32;
}
#endif
// semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/h.pch

View File

@@ -1 +1,4 @@
// semmle-extractor-options: -Werror
#ifndef __CODEQL_TEST__
#error __CODEQL_TEST__ missing
#endif

View File

@@ -10,9 +10,13 @@
| arguments.c | 10 | --target |
| arguments.c | 11 | --edg |
| arguments.c | 12 | linux_x86_64 |
| arguments.c | 13 | --gcc |
| arguments.c | 14 | --predefined_macros |
| arguments.c | 15 | <tools>/qltest/predefined_macros |
| arguments.c | 16 | -w |
| arguments.c | 17 | -Werror |
| arguments.c | 18 | arguments.c |
| arguments.c | 13 | --edg |
| arguments.c | 14 | -D |
| arguments.c | 15 | --edg |
| arguments.c | 16 | __CODEQL_TEST__ |
| arguments.c | 17 | --gcc |
| arguments.c | 18 | --predefined_macros |
| arguments.c | 19 | <tools>/qltest/predefined_macros |
| arguments.c | 20 | -w |
| arguments.c | 21 | -Werror |
| arguments.c | 22 | arguments.c |

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