Compare commits

...

431 Commits

Author SHA1 Message Date
Jean Helie
998ce38584 fix RequestForgeryConfig access 2023-04-20 16:02:10 +02:00
tiferet
69974611f9 Add read-file MaD sinks as known tainted path sinks. 2023-04-20 15:45:53 +02:00
tiferet
7fa039468c Update automodel code after the Java config revamp 2023-04-20 15:45:53 +02:00
tiferet
c35e9391ed Update TaintedPathConfig after rebase on main 2023-04-20 15:45:53 +02:00
tiferet
906b922a1c Delete unneeded imports 2023-04-20 15:45:53 +02:00
tiferet
5dcee41e65 Extract a higher percent of negative examples because some of the kinds are relatively rare. 2023-04-20 15:45:53 +02:00
tiferet
4176fefe19 Add a new sink type: command-injection 2023-04-20 15:45:53 +02:00
tiferet
e71fd1691d Add a filter that excludes an endpoint if it is unexploitable because it's a call to exists or notExists. 2023-04-20 15:45:53 +02:00
tiferet
9dae594c01 Remove last vestiges of flow from source from the query that extracts sink candidates. 2023-04-20 15:45:53 +02:00
tiferet
49d17f9964 The string of each NotASinkCharacteristic should be a clear explanation of why such endpoints are not interesting, and this should be the message exported to the sarif. 2023-04-20 15:45:53 +02:00
tiferet
a1e0f625f6 Add a subclass of EndpointCharacteristics that surfaces sinks rather than negative examples. Make all the existing ones inherit from this one. 2023-04-20 15:45:52 +02:00
tiferet
0dcd2b8765 Add a negative characteristic that filters out calls to undocumented methods in undocumented classes inside the current DB. 2023-04-20 15:45:52 +02:00
tiferet
3df95904c8 Break up hasMetadata into one predicate that extracts information and another that concatenates it into a string of the needed format, so that we can reuse the information-extraction predicate for other purposes. 2023-04-20 15:45:52 +02:00
tiferet
45058e2954 Another small fix to the syntax of the extracted MaD declarations. 2023-04-20 15:45:52 +02:00
tiferet
8c02838c38 Add a negative characteristic that filters out calls for which the package the call originates from and the package where the callee is defined are the same up to at least three levels, and the callee package is at least four levels deep. 2023-04-20 15:45:52 +02:00
tiferet
0ab09de797 Add a negative characteristic that filters out non-public methods. 2023-04-20 15:45:52 +02:00
tiferet
f715e2f58d Add a class of filters indicating not necessarily that an endpoint is not a sink, but rather that it’s not a sink that’s interesting to model in the standard Java libraries. 2023-04-20 15:45:52 +02:00
tiferet
20b0fc7b2c Remove IsConstantExpressionCharacteristic, because the value passed into the argument has nothing to do with whether or not that argument is a sink. 2023-04-20 15:45:52 +02:00
tiferet
17a6c992e7 Add a filter that excludes an endpoint if it is unexploitable. 2023-04-20 15:45:52 +02:00
tiferet
2ab175e603 Add a filter that excludes an endpoint if it's a non-sink argument to a method whose sinks have already been modeled. 2023-04-20 15:45:51 +02:00
tiferet
4ea3887c6c Promote NeutralModelCharacteristic from LikelyNotASinkCharacteristic to NotASinkCharacteristic. 2023-04-20 15:45:51 +02:00
tiferet
9ffd984677 Fixes to the syntax of the extracted MaD declarations. 2023-04-20 15:45:51 +02:00
tiferet
fbc9f4090e Downgrade CreatePathSinkCharacteristic to medium confidence. 2023-04-20 15:45:51 +02:00
tiferet
77f85b3a0d Add a negative characteristic that indicates that an endpoint was manually modeled as a neutral model. 2023-04-20 15:45:51 +02:00
tiferet
ddadc273a3 Add an endpoint filter that indicates that an endpoint is not a to node for any known taint step. Such a node cannot be tainted, because taint can't flow into it. 2023-04-20 15:45:51 +02:00
tiferet
9685963b1c Add an endpoint filter to filter out MaD-modeled taint steps.
This filter currently has some overlap with `CreatePathSinkCharacteristic`. We add a flag to `erroneousEndpoints` such that these known modeling errors can optionally be ignored.

We turn the flag off when extracting prompt examples, to ensure the prompt contains only examples we're highly certain about.

If there are errors even with this flag turned on, we return an error message in the query that extracts positive examples, to prevent us from accidentally running it when there's a codex-generated data extension file in `java/ql/lib/ext`.
2023-04-20 15:45:51 +02:00
tiferet
3fe67d9b86 Cleanup of EndpointCharacteristics, to get rid of historical naming such as "endpoint filters" and of classes that are used nowhere. 2023-04-20 15:45:51 +02:00
tiferet
1cf2769358 Rename AtmConfig to AtmConfigs and fix some imports. 2023-04-20 15:45:51 +02:00
tiferet
e9846c59a7 Rename isEffectiveSink to isSinkCandidate 2023-04-20 15:45:51 +02:00
tiferet
1e80a556ae Replace EndpointType with either SinkType or SourceType wherever possible. 2023-04-20 15:45:50 +02:00
tiferet
68c6b59fca Simplify AtmConfig:
- We no longer create new configs for each query we want to boost with ATM.
- Instead the `AtmConfig` module imports the configs for the Java queries it can and copies the configs for the ones that are defined in a ql file.
- The predicates that used to be defined in the `AtmConfig` class are now defined either in candidate extraction query or(in the case of `isKnownSink` which is used in more than one file) in `EndpointCharacteristic.qll`.
- Delete all the derived classes of AtmConfig.
- Surface all candidates that pass the endpoint filters, regardless of flow from a source.
2023-04-20 15:45:50 +02:00
tiferet
483cd5f795 EndpointType.getKind is final and just returns this. The name of the endpoint type is its MaD kind. Human-readable descriptions of these kinds are encoded only in Python, not in CodeQL. 2023-04-20 15:45:50 +02:00
tiferet
2c941a16e1 Get rid of EndpointType.getDescription 2023-04-20 15:45:50 +02:00
tiferet
1525c67fee Delete some commented out code that was copied directly from JS 2023-04-20 15:45:50 +02:00
tiferet
9205992bd7 Delete EndpointType.getEncoding, which is not needed anywhere.
If we need this down the line for model training, we can add it back in then.
2023-04-20 15:45:50 +02:00
tiferet
7a3f44b754 Delete EndpointType.getEncoding, which is not needed anywhere.
If we need this down the line for model training, we can add it back in then.
2023-04-20 15:45:50 +02:00
tiferet
68aef3a791 Improve EndpointTypes:
- Create two derived classes for EndpointType: SinkType and SourceType.
- EndpointTypes don't use a `newtype`, but rather extend string, with their characteristic predicate replacing the current getDescription predicate.
2023-04-20 15:45:50 +02:00
tiferet
2b8bc24bb2 List the MaD provenance as "ai-generated" rather than "manual"
See https://github.com/github/codeql/pull/12228
2023-04-20 15:45:50 +02:00
tiferet
794fb8995e Improve positive prompt examples:
Include only sinks that are arguments to an external API call, because these are the sinks we are most interested in.
2023-04-20 15:45:49 +02:00
tiferet
ca32281f65 Remove IsMaDTaintStepCharacteristic for now because it's catching all our known sinks as well as taint steps 2023-04-20 15:45:49 +02:00
tiferet
7cc2830768 Add endpoint filters:
- Filter out MaD taint steps
2023-04-20 15:45:49 +02:00
tiferet
878759e87a Remove redundancy from ExceptionCharacteristic 2023-04-20 15:45:49 +02:00
tiferet
c71217ed5b Add endpoint filters:
- Filter out exceptions
- Filter out endpoints in test files
2023-04-20 15:45:49 +02:00
tiferet
27b7bbc7fd As part of the metadata extraction predicate, surface whether or not the argument is being passed to an external API 2023-04-20 15:45:49 +02:00
tiferet
70ab280fce Switch back to one sink type per supported query, rather than existing MaD kinds. 2023-04-20 15:45:49 +02:00
tiferet
9b1f3ff026 Small bug fix for handling queries with multiple sink types:
`getAReasonSinkExcluded` excludes endpoints that have a characteristic that implies they're not sinks for this particular sink type _for every sink type relevant to this query_.
2023-04-20 15:45:49 +02:00
tiferet
3e728a7789 Fix a bug that allowed some known sinks to end up as sink candidates for codex 2023-04-20 15:45:49 +02:00
tiferet
0f92be72b6 In the MaD data, set the subtypes field to false for final classes / methods. 2023-04-20 15:45:49 +02:00
tiferet
750ae23a79 Create a new class other sink:
See https://github.com/github/atm-codex/pull/3

- Add a sink type `OtherMaDSinkType`, and corresponding characteristic `OtherMaDSinkCharacteristic`, for other sinks modeled by a MaD `kind` but not belonging to any of the existing sink types.
- Extract positive prompt examples for the new sink type, together with the corresponding MaD `kind`.
2023-04-20 15:45:49 +02:00
tiferet
9eda07a549 Bug fix 2023-04-20 15:45:48 +02:00
tiferet
29ba00404b In the MaD data, extract the argument index as an int rather than a string wrapped up in "Argument[]" 2023-04-20 15:45:48 +02:00
tiferet
cf4befd670 Fix the MaD signature to the correct format 2023-04-20 15:45:48 +02:00
tiferet
9f74dc17fa Separate out the sink types to align with the MaD kinds that currently exist, adding a sink type for all sinks of a given query that are not currently mapped in the MaD kinds. 2023-04-20 15:45:48 +02:00
tiferet
6cf81b80cc Add support for multiple sink types per query 2023-04-20 15:45:48 +02:00
tiferet
8c56e9f7bd As part of the metadata extraction predicate, surface whether or not the callee is a public method 2023-04-20 15:45:48 +02:00
tiferet
cf4b461c77 Refactor the CodeQL code that extracts metadata for methods presented to Codex, to make it easy to add another field 2023-04-20 15:45:48 +02:00
tiferet
10faf9ae3f Refactor the CodeQL code that extracts metadata for methods presented to Codex, to make it easy to add another field 2023-04-20 15:45:48 +02:00
tiferet
c5e436b4c6 Make the endpoint filter to filter out flow steps in Java a bit broader, and document it 2023-04-20 15:45:48 +02:00
tiferet
d3b222988e Add an endpoint filter to filter out flow steps 2023-04-20 15:45:48 +02:00
tiferet
3993ea9966 When extracting positive and negative examples for the Java prompt, extract the data used in the MaD extensible predicate.
This will enable the codex prompt to optionally use this data in additional columns.
2023-04-20 15:45:47 +02:00
tiferet
63f53eac98 Resolve two TODO items 2023-04-20 15:45:47 +02:00
tiferet
afed4a058d Exclude negative examples that are type access nodes.
These will never be on a flow path so they're not useful negative examples.
2023-04-20 15:45:47 +02:00
tiferet
8e4882955a Increase diversity of negative prompt examples by creating finer sub-types 2023-04-20 15:45:47 +02:00
tiferet
467f648ea6 If a node satisfies the logic for both isSink and isSanitizer, don't include it as a positive or negative example in the prompt, because it's too ambiguous and will confuse the model. 2023-04-20 15:45:47 +02:00
tiferet
3009249ba9 Simplify the definition of ExtractPositiveExamples.ql 2023-04-20 15:45:47 +02:00
tiferet
627d5f4f8c Avoid accidentally extracting positive prompt examples when there is a codex-generated data extension file in java/ql/lib/ext 2023-04-20 15:45:47 +02:00
tiferet
436b790dc1 Add a predicate that finds endpoints with logically-inconsistent characteristics, and exclude such endpoints from both positive and negative examples extracted for the codex prompt. 2023-04-20 15:45:47 +02:00
tiferet
3d4e615361 Fix codeql-pack.lock.yml so it's not looking for an ML model 2023-04-20 15:45:47 +02:00
tiferet
193ad2345c Typo fix 2023-04-20 15:45:47 +02:00
tiferet
dd82838d7a Delete TODO items that are done 2023-04-20 15:45:46 +02:00
tiferet
3bc1ace37d Have each EndpointType keep track of the sink/source kind for this endpoint type as used in Models as Data 2023-04-20 15:45:46 +02:00
tiferet
4d3bcb9d61 Fix the extraction of data for the data extension YML file. 2023-04-20 15:45:46 +02:00
tiferet
51973db0f3 Add data needed for the data extension YML file to ExtractSinkCandidatesWithFlow.ql: first pass. 2023-04-20 15:45:46 +02:00
tiferet
cffae3b441 Small update to SafeExternalApiMethodCharacteristic 2023-04-20 15:45:46 +02:00
tiferet
464e950166 Improvements to ExtractSinkCandidatesWithFlow.ql 2023-04-20 15:45:46 +02:00
tiferet
3032a00a0a Minor improvement 2023-04-20 15:45:46 +02:00
tiferet
d37b5f9e1e Improvements to ExtractSinkCandidatesWithFlow.ql 2023-04-20 15:45:46 +02:00
tiferet
8bd932cc82 Delete the queries the Java team isn't currently interested in boosting 2023-04-20 15:45:46 +02:00
tiferet
6f7109000f Move isFlowLikelyInBaseQuery to the ATMConfig and delete AdaptiveThreatModeling.qll 2023-04-20 15:45:46 +02:00
tiferet
fdb8e94d23 Rename request forgery sink to server-side request forgery sink 2023-04-20 15:45:45 +02:00
tiferet
26daa1abb5 Add and implementation of request forgery sinks and corresponding positive EndpointCharacteristic in Java 2023-04-20 15:45:45 +02:00
tiferet
385d5cf50c Bug fixes 2023-04-20 15:45:45 +02:00
tiferet
2e1d733b0c Add an implementation of TaintedPathATM.qll and corresponding positive EndpointCharacteristic in Java 2023-04-20 15:45:45 +02:00
tiferet
fcace2a82b Subsample negative examples to 1% to prevent huge numbers. 2023-04-20 15:45:45 +02:00
tiferet
8643d9b4bb Add a Java NotASinkCharacteristic safe external API method 2023-04-20 15:45:45 +02:00
tiferet
b530d4f440 Add queries to surface high-confidence Java sinks and non-sinks to use as examples in the codex prompt. 2023-04-20 15:45:45 +02:00
tiferet
b5f6b98706 Rewrite ExtractSinkCandidatesWithFlow.ql as a problem query so we can run it with codeql database analyze to output SARIF results. 2023-04-20 15:45:45 +02:00
tiferet
dccddd6a93 Add a couple of endpoint filters for Java 2023-04-20 15:45:45 +02:00
tiferet
488763cc3d Try implementing SqlInjectionATM.qll in Java 2023-04-20 15:45:45 +02:00
tiferet
c3e7161741 Start making the additions needed to surface candidate Java sinks for codex classification outside the evaluator. 2023-04-20 15:45:45 +02:00
tiferet
5bc08bad54 Go back to the prompt of https://github.com/github/codeql-dca-main/issues/9475 2023-04-20 15:45:44 +02:00
tiferet
b11fc6005f Give more explicit instructions in the codex prompt, but don't solicit rare sink types. 2023-04-20 15:45:44 +02:00
tiferet
3fde31e3cf Give more explicit instructions in the codex prompt. 2023-04-20 15:45:44 +02:00
tiferet
097a1989ed Minor prompt improvements:
- Tell codex explicitly that this is JavaScript code
- Replace "Dataflow node" with "Code snippet"
2023-04-20 15:45:44 +02:00
tiferet
6510c73e04 Minor prompt improvements:
Remove spaces that break the code syntax or make for strange code styling.
2023-04-20 15:45:44 +02:00
tiferet
fd17990583 In-line predicates that are costing a lot of compute time 2023-04-20 15:45:44 +02:00
tiferet
0e5a3a427a Add a test that can be used to determine the alerts codex will surface for each query. 2023-04-20 15:45:44 +02:00
tiferet
1c472a0f4a Bug fixes for things that interfere with using the codex model 2023-04-20 15:45:44 +02:00
tiferet
d9f174ee36 Add a test that can be used to determine how well codex reproduces the manual modeling for each sink type. 2023-04-20 15:45:44 +02:00
tiferet
d3882552b6 Fix endpointScores 2023-04-20 15:45:44 +02:00
tiferet
77c2429269 Bug fix in selecting a node's location:
Locations only exist where there are locatable structures in the DB. Thus, select the largest location that contains the node and at most `neighborhoodSize` lines before and after the node.
2023-04-20 15:45:43 +02:00
tiferet
81119f4ba1 Give endpoint types more intuitive names and then use those names directly in composing the codex prompt. 2023-04-20 15:45:43 +02:00
tiferet
b8942cd775 Further improve the structure of endpoint scoring 2023-04-20 15:45:43 +02:00
tiferet
e1f639acc5 Remove tokens from the prompt that the Java side can't handle 2023-04-20 15:45:43 +02:00
tiferet
2bb034418a Change the prompt to use sink names defined in EndpointType 2023-04-20 15:45:43 +02:00
tiferet
f32401a9c8 Improve the structure of endpoint scoring 2023-04-20 15:45:43 +02:00
tiferet
8b5b7af99b Pull in the prompt work from branch tiferet/codex-prompt 2023-04-20 15:45:43 +02:00
tiferet
14c5efc9d0 Merge in aeisenberg/atm-codex 2023-04-20 15:45:43 +02:00
Michael Nebel
aa8291e13f Merge pull request #12870 from michaelnebel/csharp/refactordataflow6
C#: Re-factor data flow and taint tracking configurations to use the new API.
2023-04-20 14:31:20 +02:00
Kasper Svendsen
51b6da4183 Merge pull request #12875 from kaspersv/kaspersv/prevent-ruby-join-order-regression
Prevent Ruby join order regression
2023-04-20 13:50:40 +02:00
Erik Krogh Kristensen
377aa68bb3 Merge pull request #12854 from natejohnson05/js-insecure-http-parser
JS - NodeJS CWE-444 InsecureHTTPParser
2023-04-20 13:09:45 +02:00
Jeroen Ketema
b6a7661c7e Merge pull request #12880 from MathiasVP/use-after-free-fps
C++: Add some use-after-free FP tests
2023-04-19 20:07:10 +02:00
Nate Johnson
88411ce439 Merge branch 'main' into js-insecure-http-parser 2023-04-19 13:36:24 -04:00
Mathias Vorreiter Pedersen
533e1d818b C++: Add some use-after-free FPs. 2023-04-19 17:01:55 +01:00
Geoffrey White
7285704807 Merge pull request #12876 from geoffw0/extensiondecl
Swift: Improve ExtensionDecl.toString
2023-04-19 16:41:48 +01:00
Geoffrey White
e895cac569 Merge pull request #12877 from geoffw0/deprecated
Swift: Delete deprecated classes
2023-04-19 16:41:25 +01:00
Geoffrey White
3779d8423f Swift: Autoformat. 2023-04-19 14:57:17 +01:00
Jeroen Ketema
aa3e8d6b87 Merge pull request #12815 from jketema/anon
C++: Update test expectations after extractor changes
2023-04-19 15:51:56 +02:00
Geoffrey White
4484574301 Swift: Rename clashing CleartextStorage modules. 2023-04-19 14:29:25 +01:00
Geoffrey White
10c222e7e2 Swift: Remove deprecated classes from queries. 2023-04-19 14:26:03 +01:00
Geoffrey White
a3c66b6032 Merge pull request #12833 from geoffw0/addmodels
Swift: Add some sink models
2023-04-19 14:18:29 +01:00
Geoffrey White
49dccaa89d Swift: Fix other tests. 2023-04-19 14:16:24 +01:00
Owen Mansel-Chan
23934292f0 Merge pull request #12834 from owen-mc/go/refactor-autobuilder
Go: Refactor autobuilder
2023-04-19 14:10:23 +01:00
Owen Mansel-Chan
65c1f4a151 Merge pull request #12873 from owen-mc/go/fix-platform-specific-tests
Go: Fix platform specific tests
2023-04-19 13:52:14 +01:00
Kasper Svendsen
ba6bb79dd3 Prevent Ruby join order regression 2023-04-19 14:42:27 +02:00
Geoffrey White
e9ffefaa96 Swift: Improve ExtensionDecl.toString. 2023-04-19 13:38:04 +01:00
Jeroen Ketema
1a876f7762 C++: Update test expectations after extractor changes 2023-04-19 14:12:00 +02:00
Owen Mansel-Chan
3ca04338ca Use named initialization for struct 2023-04-19 13:06:51 +01:00
Paolo Tranquilli
c2f2a0578b Merge pull request #12868 from github/redsun82/bazel-6.1.2
Bazel: update to 6.1.2
2023-04-19 14:06:08 +02:00
Owen Mansel-Chan
219c1686fd Wrap return values of moveToTemporaryGopath in a struct 2023-04-19 12:40:23 +01:00
Erik Krogh Kristensen
d7325ba4e1 Merge pull request #12856 from p-/p--non-constant-open-improvments
Ruby: Add additional sanitizers for Kernel.open or IO.read or similar sinks with a non-constant value
2023-04-19 13:39:16 +02:00
Michael Nebel
b410791f28 C#: Re-factor InsecureRandomness to use the new API. 2023-04-19 13:36:30 +02:00
Michael Nebel
e94b492404 C#: Delete inaccessible/dead data flow configuration in JsonWebTokenHandlerLib. 2023-04-19 13:36:30 +02:00
Michael Nebel
f976eeb909 C#: Re-factor on AppendCookieTracking to use the new API. 2023-04-19 13:36:30 +02:00
Michael Nebel
1b128a21e6 C#: Re-factor AuthCookieName to use the new API. 2023-04-19 13:36:30 +02:00
Michael Nebel
1979a78f02 C#: Re-factor RequestForgery to use the new API. 2023-04-19 13:36:30 +02:00
Michael Nebel
b7e36b7dec C#: Re-factor NoDisposeCallOnLocalIDisposable to use the new API. 2023-04-19 13:36:30 +02:00
Michael Nebel
5580023ec3 C#: Re-factor FormatInvalid to use the new API. 2023-04-19 13:36:30 +02:00
Owen Mansel-Chan
1bb006f43e Move defer statements to the right place
It turns out that extracting defer statements into a separate function
changes behaviour.
2023-04-19 12:20:52 +01:00
Owen Mansel-Chan
641f16b0df Factor out extract() 2023-04-19 12:20:52 +01:00
Owen Mansel-Chan
a611769b43 Factor out installDependencies() 2023-04-19 12:20:51 +01:00
Owen Mansel-Chan
d61d595b21 Factor out function buildWithCustomCommands 2023-04-19 12:20:51 +01:00
Owen Mansel-Chan
b45c0ff848 Factor out buildWithoutCustomCommands 2023-04-19 12:20:51 +01:00
Owen Mansel-Chan
b76e655735 Factor out moving code to temp dir in gopath 2023-04-19 12:20:50 +01:00
Owen Mansel-Chan
ba48eaa8a6 Factor out calculation of source dir 2023-04-19 12:20:50 +01:00
Owen Mansel-Chan
702c22b630 Refactor calculation of inLGTM 2023-04-19 12:20:49 +01:00
Owen Mansel-Chan
f0186957ca Factor out tryUpdateGoModAndGoSum 2023-04-19 12:20:49 +01:00
Owen Mansel-Chan
0bfb242e63 Factor out logic for needGopath 2023-04-19 12:20:49 +01:00
Owen Mansel-Chan
b169f1bfdf Factor out code to fix go vendor issues 2023-04-19 12:20:48 +01:00
Owen Mansel-Chan
f872a11b85 Factor out initial ModMode calculation 2023-04-19 12:20:48 +01:00
Owen Mansel-Chan
2d8d9773c4 Factor out depMode calculation 2023-04-19 12:20:47 +01:00
Owen Mansel-Chan
d613bc8a28 Update checks for files or dirs existing
The previous way is considered outdated now.
2023-04-19 12:20:47 +01:00
Geoffrey White
c092851c28 Swift: Add a test for ExtensionDecls. 2023-04-19 11:50:49 +01:00
Owen Mansel-Chan
2914480ff6 Avoid platform-specific results
These were introduced in https://github.com/github/codeql/pull/12750 but
the relevant tests that should have caught it weren't run.
2023-04-19 11:18:19 +01:00
Owen Mansel-Chan
1cf626f712 Use latest patch version of Go 1.20 for tests 2023-04-19 11:18:09 +01:00
Tony Torralba
4e60697042 Merge pull request #12866 from github/workflow/coverage/update
Update CSV framework coverage reports
2023-04-19 11:16:21 +02:00
Paolo Tranquilli
83674751fc Bazel: update to 6.1.2 2023-04-19 11:12:02 +02:00
Mathias Vorreiter Pedersen
8d62d5916e Merge pull request #12807 from MathiasVP/dataflow-for-keypaths
Swift: Dataflow for keypaths
2023-04-19 10:00:49 +01:00
Peter Stöckli
672cb92fbd Ruby: improve non-constant-kernel-open, recursive step for freeze
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2023-04-19 10:50:59 +02:00
Harry Maclean
c44fbc1063 Merge pull request #12786 from hmac/merge-extractor-binaries
Ruby/QL: Merge extractor binaries
2023-04-19 15:17:25 +07:00
Michael Nebel
1caca21552 Merge pull request #12829 from michaelnebel/csharp/refactordataflow4
C#: Re-factor tainttracking and dataflow configurations to use the new API.
2023-04-19 08:32:36 +02:00
Harry Maclean
30468dd059 QL: Rename extractor to codeql-extractor-ql 2023-04-19 06:30:09 +00:00
Harry Maclean
ab4eba11ec Ruby: Rename extractor to codeql-extractor-ruby 2023-04-19 06:27:27 +00:00
Tony Torralba
62f5a5dcd5 Merge pull request #10707 from atorralba/atorralba/log-injection-sanitizers
Java: Add line break sanitizers to java/log-injection
2023-04-19 08:20:04 +02:00
Nate Johnson
4ae8377713 Merge branch 'main' into js-insecure-http-parser 2023-04-18 22:00:13 -04:00
Nate Johnson
78229bb264 Moved into experimental 2023-04-18 21:59:14 -04:00
github-actions[bot]
7abc029872 Add changed framework coverage reports 2023-04-19 00:16:15 +00:00
Mathias Vorreiter Pedersen
9aca2d8533 Merge pull request #12861 from MathiasVP/ignore-more-instructions-for-dataflow
C++: Ignore a few more instructions in dataflow
2023-04-18 18:17:11 +01:00
Geoffrey White
c7ea08aa73 Swift: Fix inline expectations. 2023-04-18 17:32:38 +01:00
Mathias Vorreiter Pedersen
fb1a871777 Merge pull request #12855 from MathiasVP/fix-joins-in-use-after-free
C++: Fix bad self-join in `cpp/use-after-free`
2023-04-18 17:13:03 +01:00
Edward Minnix III
09502c60d5 Merge pull request #12812 from egregius313/egregius313/java/dataflow/refactor-tests
Java: Refactor Test DataFlow configurations to new API
2023-04-18 10:22:30 -04:00
Alex Ford
924ce250dd Merge pull request #12847 from github/post-release-prep/codeql-cli-2.13.0
Post-release preparation for codeql-cli-2.13.0
2023-04-18 14:40:40 +01:00
Mathias Vorreiter Pedersen
6e5f09f7bb C++: Ignore more instructions in dataflow. 2023-04-18 13:32:24 +01:00
Mathias Vorreiter Pedersen
231b0fcab2 Swift: Add more tests. 2023-04-18 12:01:08 +01:00
Peter Stöckli
2f268b309b Ruby: improve non-constant-kernel-open, freeze called on constant 2023-04-18 11:24:01 +02:00
Tony Torralba
ba49386e6c Merge pull request #12806 from GeekMasher/main
Java: Add missing write-file models for Java IO / NIO
2023-04-18 11:15:53 +02:00
Mathias Vorreiter Pedersen
61aba4683f C++: Fix bad self-join in 'cpp/use-after-free'.
Before:
```ql
[2023-04-18 09:17:24] Evaluated non-recursive predicate _ValueNumberingInternal#c9f42560::tvalueNumber#1#ff_10#join_rhs_project#Instruction#577b6a83::Initia__#loop_invariant_prefix@ae046923 in 3903ms (size: 130544).
Evaluated relational algebra for predicate _ValueNumberingInternal#c9f42560::tvalueNumber#1#ff_10#join_rhs_project#Instruction#577b6a83::Initia__#loop_invariant_prefix@ae046923 with tuple counts:
        533787724  ~0%    {2} r1 = JOIN ValueNumberingInternal#c9f42560::tvalueNumber#1#ff_10#join_rhs WITH ValueNumberingInternal#c9f42560::tvalueNumber#1#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1
           130544  ~0%    {2} r2 = JOIN r1 WITH project#Instruction#577b6a83::InitializeParameterInstruction#ff ON FIRST 1 OUTPUT Lhs.1, Lhs.0
                          return r2
```

After:
```ql
[2023-04-18 10:09:34] Evaluated non-recursive predicate _ValueNumberingInternal#c9f42560::tvalueNumber#1#ff_project#Instruction#577b6a83::InitializeParamete__#loop_invariant_prefix@eb90a6fk in 2ms (size: 18380).
Evaluated relational algebra for predicate _ValueNumberingInternal#c9f42560::tvalueNumber#1#ff_project#Instruction#577b6a83::InitializeParamete__#loop_invariant_prefix@eb90a6fk with tuple counts:
        18380  ~0%    {2} r1 = JOIN ValueNumberingInternal#c9f42560::tvalueNumber#1#ff WITH project#Instruction#577b6a83::InitializeParameterInstruction#ff ON FIRST 1 OUTPUT Lhs.1, Lhs.0
                      return r1
```
2023-04-18 10:14:45 +01:00
Arthur Baars
e5d89b969a Merge pull request #12780 from aibaars/shared-yaml-lib
JS: extract YAML library to a shared pack
2023-04-18 11:09:53 +02:00
Tom Hvitved
f6d000eb20 Merge pull request #12805 from hvitved/remove-queries-xml
Remove all `queries.xml` files
2023-04-18 10:52:14 +02:00
Peter Stöckli
0a6bb3f7ce Ruby: improve non-constant-kernel-open, no FP's on open without arguments 2023-04-18 10:10:36 +02:00
Paolo Tranquilli
d777fd950f Merge pull request #12760 from github/redsun82/swift-logging-compiler
Swift: route compiler diagnostics through our log
2023-04-18 10:03:29 +02:00
Tony Torralba
99ad43b21e Merge pull request #12853 from github/workflow/coverage/update
Update CSV framework coverage reports
2023-04-18 09:34:52 +02:00
Kasper Svendsen
9d34d090ab Merge pull request #12843 from kaspersv/kaspersv/prevent-bad-js-join-order
Prevent JS join order regression
2023-04-18 09:09:43 +02:00
Paolo Tranquilli
b8c55612e5 Swift: route compiler diagnostics through our log 2023-04-18 08:46:31 +02:00
Nate Johnson
bbb1ee9597 Merge branch 'main' into js-insecure-http-parser 2023-04-18 00:45:32 -04:00
Nate Johnson
cb90f9af3c Fix to include specification of flag in NODE_OPTIONS 2023-04-18 00:41:48 -04:00
Nate Johnson
522a285d9e Qhelp file for explanation 2023-04-18 00:41:28 -04:00
Nate Johnson
2e27447c65 Include example 2023-04-18 00:41:11 -04:00
Ed Minnix
e6a2528c38 Refactor XSS and SpringJDBC tests to lib configurations 2023-04-17 23:48:06 -04:00
Ed Minnix
49521f6de8 Refactor tests which extends Configuration 2023-04-17 23:48:06 -04:00
Ed Minnix
66f971e70d Refactor query tests 2023-04-17 23:48:06 -04:00
Ed Minnix
93bd2a9409 Refactor PathSanitizer test 2023-04-17 23:48:06 -04:00
Ed Minnix
547f00c3d1 Refactor Spring test 2023-04-17 23:48:06 -04:00
Ed Minnix
9631b6545f Refactor Ratpack test 2023-04-17 23:48:06 -04:00
Ed Minnix
e0e5bb131b Refactor RabbitMQ test 2023-04-17 23:48:06 -04:00
Ed Minnix
2579852e90 Refactor jms test 2023-04-17 23:48:06 -04:00
Ed Minnix
6cda285d56 Refactor Guice test 2023-04-17 23:48:06 -04:00
Ed Minnix
8d0e3ac033 Refactor Guava test 2023-04-17 23:48:06 -04:00
Ed Minnix
38e65ee36d Refactor apache-http test 2023-04-17 23:48:06 -04:00
Ed Minnix
f745642252 Refactor Android tests 2023-04-17 23:48:06 -04:00
Ed Minnix
95c28967cc Refactor dataflow library tests 2023-04-17 23:48:06 -04:00
Ed Minnix
0c380cdd72 Formatting fixes 2023-04-17 23:48:06 -04:00
Ed Minnix
13ec7db1ea Kotlin tests 2023-04-17 23:48:06 -04:00
github-actions[bot]
3c2a3abb13 Add changed framework coverage reports 2023-04-18 00:15:30 +00:00
Erik Krogh Kristensen
03e76378ca Merge pull request #12850 from smiddy007/remove-unused-example-files
JS: Remove unused example files and edit qhelp to match
2023-04-17 23:29:15 +02:00
Jami
a149c41baf Merge pull request #12155 from jcogs33/jcogs33/add-heuristic-ssrf-models
Java: add ssrf models discovered with heuristics
2023-04-17 15:45:48 -04:00
Mathias Vorreiter Pedersen
bb8c3de6b2 Merge pull request #12599 from rdmarsh2/rdmarsh2/range-analysis-overflow
C++: add overflow detection to new range analysis
2023-04-17 20:18:44 +01:00
Jami Cogswell
25786f61be Java: minorAnalysis in change note 2023-04-17 13:48:04 -04:00
smiddy007
e4ec1ae261 Update InsufficientPasswordHash.qhelp
change file name to original
2023-04-17 13:18:47 -04:00
smiddy007
88d2f65c5f Rename InsufficientPasswordHash_NodeJS_fixed.js to InsufficientPasswordHash_fixed.js 2023-04-17 13:17:13 -04:00
smiddy007
cbe45f7e55 Rename InsufficientPasswordHash_NodeJS.js to InsufficientPasswordHash.js 2023-04-17 13:16:57 -04:00
smiddy007
36d7370998 Delete InsufficientPasswordHash_CryptoJS_fixed
file not used in qhelp
2023-04-17 13:16:25 -04:00
smiddy007
e65daaae49 Delete InsufficientPasswordHash_CryptoJS.js
not used in qhelp file
2023-04-17 13:15:10 -04:00
Mathias Vorreiter Pedersen
d833850850 C++: another 'fix test after module rename'. 2023-04-17 17:48:22 +01:00
github-actions[bot]
648f0e19ec Post-release preparation for codeql-cli-2.13.0 2023-04-17 15:39:24 +00:00
Robert Marsh
2b41aef6a7 C++: autoformat 2023-04-17 11:36:17 -04:00
Robert Marsh
ea7996f1bb C++: fix test after module rename 2023-04-17 11:30:04 -04:00
Arthur Baars
048fb8b953 Add change note 2023-04-17 16:43:21 +02:00
Mathew Payne
3526b74ce7 Merge branch 'main' into main 2023-04-17 15:10:32 +01:00
Mathias Vorreiter Pedersen
d975ceb648 Merge pull request #12818 from MathiasVP/dataflow-for-missing-scanf-qery
C++: Use the new dataflow library in `cpp/missing-check-scanf`
2023-04-17 14:34:11 +01:00
Paolo Tranquilli
901db73d55 Merge pull request #12745 from github/redsun82/swift-logging
Swift: introduce usage of binlog
2023-04-17 15:23:29 +02:00
Asger F
5272810ad9 Merge pull request #12826 from asgerf/js/more-call-graph-steps
JS: Improvements to type-tracking through 'extend' and 'this'
2023-04-17 13:50:59 +02:00
Mathew Payne
44c1b48f94 Merge branch 'main' into main 2023-04-17 12:40:23 +01:00
Mathew Payne
c77cdcf4c3 Removed the OutputStream models 2023-04-17 11:38:28 +00:00
Kasper Svendsen
ad82433a88 Prevent JS join order regression 2023-04-17 13:24:19 +02:00
Arthur Baars
34d3040ce2 Add change note 2023-04-17 12:59:14 +02:00
Asger F
13b1e97caa JS: Fix the ExtendCall restriction 2023-04-17 12:30:08 +02:00
Asger F
eafef91dbc JS: Update test output after ExtendCall restriction 2023-04-17 12:28:23 +02:00
Asger F
024760610a JS: Add prototype pollution test 2023-04-17 12:27:34 +02:00
Asger F
2f4a181a7d JS: revert path sanitizers in proto pollution query 2023-04-17 12:21:00 +02:00
Asger F
04079752f7 JS: update test output after adding 'this' sanitizer 2023-04-17 12:15:46 +02:00
Asger F
f87f6c8556 JS: Add test to unsafe jquery plugin 2023-04-17 12:15:05 +02:00
Asger F
b728f71b4b JS: Move 'this' sanitizer to customizations 2023-04-17 12:11:18 +02:00
Michael Nebel
e8e25b8e55 C#: Re-factor HashWithoutSalt to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
c7b0ae8490 C#: Re-factor the CollectionFlow test to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
518aceba64 Re-factor the Types testcase to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
388cb704d0 C#: Re-factor the CallSensitivityFlow test to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
eaddb627ef C#: Re-factor the GlobalFlow test to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
73ddc0530a C#: Re-factor InsecureSqlConnection to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
3687770dab C#: Re-factor AddCertToRootStore to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
ec68e91ba9 C#: Re-factor LambdaDataFlow to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
49d335695a C#: Re-factor FlowToDataSerializerConstructor to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
5964daa44d C#: Re-factor FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
a4ee35302d C#: Re-factor CookieOptionsTracking to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
b3de105665 C#: Re-factor TypeNameTracking to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
ee7d15ac5d C#: Re-factor ExponentialRegexDataFlow to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
8d5ca53126 C#: Re-refactor another SettingsDataFlow to use the new API. 2023-04-17 11:38:37 +02:00
Michael Nebel
5b8544343b C#: Re-factor SettingsDataFlow to use the new API. 2023-04-17 11:38:36 +02:00
Michael Nebel
5ea6cea894 C#: Re-factor DapperCommandDefinitionMethodCallSqlExpr to use the new API. 2023-04-17 11:38:36 +02:00
Paolo Tranquilli
fdd975b992 Merge pull request #12842 from github/redsun82/swift-qlgen-qldoc
Swift: add QLdoc for generated `Raw` and `Synth` modules
2023-04-17 10:57:54 +02:00
Mathias Vorreiter Pedersen
2a14479bf3 C++: Autoformat. 2023-04-17 09:34:44 +01:00
Mathias Vorreiter Pedersen
a87e67d89d C++: Fix join orders.
Before:

```
Tuple counts for RangeAnalysisStage#38d7ce80::RangeStage#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisImpl#edd69a76::ConstantBounds#FloatDelta#0eab55d1::FloatOverflow#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::potentiallyOverflowingExpr#2#ff/2@36ed7auu after 42.1s:
    365        ~0%     {2} r1 = JOIN num#SemanticOpcode#e6f455a5::TNegate#f WITH SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs ON FIRST 1 OUTPUT false, Rhs.1 'expr'

    0          ~0%     {2} r2 = JOIN num#SemanticOpcode#e6f455a5::TSubOne#f WITH SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs ON FIRST 1 OUTPUT false, Rhs.1 'expr'

    365        ~0%     {2} r3 = r1 UNION r2

    0          ~0%     {2} r4 = JOIN num#SemanticOpcode#e6f455a5::TAddOne#f WITH project#SemanticExpr#91573b9a::SemKnownExpr#class#fff_10#join_rhs ON FIRST 1 OUTPUT true, Rhs.1 'expr'

    2          ~0%     {2} r5 = JOIN m#RangeAnalysisStage#38d7ce80::RangeStage#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisImpl#edd69a76::ConstantBounds#FloatDelta#0eab55d1::FloatOverflow#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::boundedPhiInp1#6#ffbfff WITH num#SemanticOpcode#e6f455a5::TMul#f CARTESIAN PRODUCT OUTPUT Rhs.0, Lhs.0 'positively'
    22026      ~0%     {2} r6 = JOIN r5 WITH SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs ON FIRST 1 OUTPUT Lhs.1 'positively', Rhs.1 'expr'

    2          ~0%     {2} r7 = JOIN m#RangeAnalysisStage#38d7ce80::RangeStage#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisImpl#edd69a76::ConstantBounds#FloatDelta#0eab55d1::FloatOverflow#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::boundedPhiInp1#6#ffbfff WITH num#SemanticOpcode#e6f455a5::TShiftLeft#f CARTESIAN PRODUCT OUTPUT Rhs.0, Lhs.0 'positively'
    1978       ~0%     {2} r8 = JOIN r7 WITH SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs ON FIRST 1 OUTPUT Lhs.1 'positively', Rhs.1 'expr'

    24004      ~0%     {2} r9 = r6 UNION r8
    24004      ~0%     {2} r10 = r4 UNION r9
    24369      ~0%     {2} r11 = r3 UNION r10

    2726       ~1%     {2} r12 = JOIN project#SemanticExpr#91573b9a::SemDivExpr#fffff WITH project#SemanticExpr#91573b9a::SemKnownExpr#class#fff#2 ON FIRST 1 OUTPUT Rhs.1, Lhs.0 'expr'
    1900       ~2%     {2} r13 = JOIN r12 WITH SemanticType#3725723c::SemFloatingPointType#ff ON FIRST 1 OUTPUT false, Lhs.1 'expr'

    4500       ~0%     {1} r14 = JOIN SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs WITH num#SemanticOpcode#e6f455a5::TAdd#f ON FIRST 1 OUTPUT Lhs.1 'expr'

    0          ~0%     {1} r15 = JOIN SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs WITH num#SemanticOpcode#e6f455a5::TPointerAdd#f ON FIRST 1 OUTPUT Lhs.1 'expr'

    4500       ~0%     {1} r16 = r14 UNION r15
    4000       ~0%     {2} r17 = JOIN r16 WITH project#SemanticExpr#91573b9a::SemBinaryExpr#fffff#2 ON FIRST 1 OUTPUT Rhs.1, Lhs.0 'expr'
    7000       ~0%     {2} r18 = JOIN r17 WITH SignAnalysisCommon#4b1623af::SignAnalysis#FloatDelta#0eab55d1::FloatDelta#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::semExprSign#1#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'expr'

    1264       ~0%     {2} r19 = JOIN r18 WITH num#Sign#2ecc774b::TNeg#f ON FIRST 1 OUTPUT Lhs.0, Lhs.1 'expr'
    188324151  ~0%     {2} r20 = JOIN r19 WITH SignAnalysisCommon#4b1623af::SignAnalysis#FloatDelta#0eab55d1::FloatDelta#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::semExprSign#1#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.1 'expr', Rhs.1
    1000       ~0%     {2} r21 = JOIN r20 WITH project#SemanticExpr#91573b9a::SemBinaryExpr#fffff ON FIRST 2 OUTPUT false, Lhs.0 'expr'

    2900       ~0%     {2} r22 = r13 UNION r21

    3259       ~2%     {2} r23 = JOIN r18 WITH num#Sign#2ecc774b::TPos#f ON FIRST 1 OUTPUT Lhs.0, Lhs.1 'expr'
    1521124720 ~0%     {2} r24 = JOIN r23 WITH SignAnalysisCommon#4b1623af::SignAnalysis#FloatDelta#0eab55d1::FloatDelta#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::semExprSign#1#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.1 'expr', Rhs.1
    3000       ~2%     {2} r25 = JOIN r24 WITH project#SemanticExpr#91573b9a::SemBinaryExpr#fffff ON FIRST 2 OUTPUT true, Lhs.0 'expr'
```
(I stopped evaluation midway.)

After:

```ql
Evaluated relational algebra for predicate RangeAnalysisStage#38d7ce80::RangeStage#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisImpl#edd69a76::ConstantBounds#FloatDelta#0eab55d1::FloatOverflow#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::potentiallyOverflowingExpr#2#ff@dc3a0712 with tuple counts:
  26269   ~2%    {2} r1 = _SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs_m#RangeAnalysisStage#38d7ce80::R__#shared UNION _SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs_SemanticType#3725723c::SemFloati__#shared

  26269   ~2%    {2} r2 = _num#SemanticOpcode#e6f455a5::TAddOne#f_project#SemanticExpr#91573b9a::SemKnownExpr#class#fff_10#joi__#shared UNION r1

  41333   ~1%    {2} r3 = JOIN _SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs_num#SemanticOpcode#e6f455a5::TAd__#shared WITH SignAnalysisCommon#4b1623af::SignAnalysis#FloatDelta#0eab55d1::FloatDelta#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::semExprSign#1#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1

  5806   ~2%    {2} r4 = JOIN r3 WITH num#Sign#2ecc774b::TNeg#f ON FIRST 1 OUTPUT Lhs.1, Lhs.0
  5806   ~1%    {3} r5 = JOIN r4 WITH project#SemanticExpr#91573b9a::SemBinaryExpr#fffff#2 ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0
  3612   ~0%    {2} r6 = JOIN r5 WITH SignAnalysisCommon#4b1623af::SignAnalysis#FloatDelta#0eab55d1::FloatDelta#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::semExprSign#1#ff ON FIRST 2 OUTPUT false, Lhs.2

  18476   ~1%    {2} r7 = JOIN r3 WITH num#Sign#2ecc774b::TPos#f ON FIRST 1 OUTPUT Lhs.1, Lhs.0
  18476   ~1%    {3} r8 = JOIN r7 WITH project#SemanticExpr#91573b9a::SemBinaryExpr#fffff#2 ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0
  18444   ~2%    {2} r9 = JOIN r8 WITH SignAnalysisCommon#4b1623af::SignAnalysis#FloatDelta#0eab55d1::FloatDelta#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::semExprSign#1#ff ON FIRST 2 OUTPUT true, Lhs.2

  22056   ~0%    {2} r10 = r6 UNION r9

  24137   ~2%    {2} r11 = JOIN _SemanticExpr#91573b9a::SemExpr::getOpcode#0#dispred#fb_10#join_rhs_num#SemanticOpcode#e6f455a5::TPo__#shared WITH SignAnalysisCommon#4b1623af::SignAnalysis#FloatDelta#0eab55d1::FloatDelta#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::semExprSign#1#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1

  16966   ~2%    {1} r12 = JOIN r11 WITH num#Sign#2ecc774b::TPos#f ON FIRST 1 OUTPUT Lhs.1
  16966   ~4%    {2} r13 = JOIN r12 WITH project#SemanticExpr#91573b9a::SemBinaryExpr#fffff ON FIRST 1 OUTPUT Rhs.1, Lhs.0
  24917   ~1%    {2} r14 = JOIN r13 WITH SignAnalysisCommon#4b1623af::SignAnalysis#FloatDelta#0eab55d1::FloatDelta#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::semExprSign#1#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1
  2781   ~0%    {2} r15 = JOIN r14 WITH num#Sign#2ecc774b::TNeg#f ON FIRST 1 OUTPUT false, Lhs.1

  2817   ~0%    {1} r16 = JOIN r11 WITH num#Sign#2ecc774b::TNeg#f ON FIRST 1 OUTPUT Lhs.1
  2817   ~0%    {2} r17 = JOIN r16 WITH project#SemanticExpr#91573b9a::SemBinaryExpr#fffff ON FIRST 1 OUTPUT Rhs.1, Lhs.0
  6922   ~0%    {2} r18 = JOIN r17 WITH SignAnalysisCommon#4b1623af::SignAnalysis#FloatDelta#0eab55d1::FloatDelta#RangeUtils#6da26777::RangeUtil#FloatDelta#0eab55d1::FloatDelta#RangeAnalysisConstantSpecific#878f81e8::CppLangImplConstant##::semExprSign#1#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1
  2765   ~1%    {2} r19 = JOIN r18 WITH num#Sign#2ecc774b::TPos#f ON FIRST 1 OUTPUT true, Lhs.1

  5546   ~0%    {2} r20 = r15 UNION r19
  27602   ~0%    {2} r21 = r10 UNION r20
  53871   ~0%    {2} r22 = r2 UNION r21
                  return r22
```
2023-04-17 09:28:31 +01:00
Paolo Tranquilli
cbe247e123 Merge branch 'main' into redsun82/swift-logging 2023-04-17 10:27:14 +02:00
Paolo Tranquilli
3f139bd93b Swift: address logging review comments 2023-04-17 10:27:01 +02:00
Paolo Tranquilli
edb355b47f Swift: add QLdoc for generated Raw and Synth modules 2023-04-17 09:38:26 +02:00
Tony Torralba
f5702f5c69 Address review comment
Handle more regex cases that cover line breaks
2023-04-17 09:33:44 +02:00
Tony Torralba
e167d3ce00 Add line break sanitizers 2023-04-17 09:33:44 +02:00
Erik Krogh Kristensen
4e49df1615 Merge pull request #12839 from jcogs33/jcogs33/update-QueryDoc-regex
QL: update regexes used in `QueryDoc.getQueryName()` and in `QueryDoc.getQueryId()/getQueryLanguage()`
2023-04-17 09:03:03 +02:00
Mathias Vorreiter Pedersen
7eee589304 Merge pull request #12569 from andersfugmann/andersfugmann/use_after_free
C++: Implement use-after-free and double-free queries using the new IR use-use dataflow
2023-04-17 08:01:58 +01:00
Mathias Vorreiter Pedersen
fa5ed04286 Update cpp/ql/src/Critical/DoubleFree.qhelp
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2023-04-17 07:40:01 +01:00
Mathias Vorreiter Pedersen
dba46bd324 Update cpp/ql/src/Critical/DoubleFree.ql
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2023-04-17 07:38:30 +01:00
Asger F
ccb57f2a84 Merge pull request #12804 from asgerf/rb/api-graphs-cached
Ruby: restrict join order of API graph predicates
2023-04-17 08:24:07 +02:00
Asger F
62dca44ee5 Update UntrustedDataToExternalAPI.expected 2023-04-17 08:23:04 +02:00
Asger F
c250ba7f27 JS: Undo sanitization of path.normalize() 2023-04-17 08:23:04 +02:00
Asger F
9db63c3a6a JS: Change note 2023-04-17 08:23:04 +02:00
Asger F
b0d4b31103 JS: Trim whitespace in test 2023-04-17 08:23:04 +02:00
Asger F
c7f16cd224 JS: Add test 2023-04-17 08:23:03 +02:00
Asger F
0d598c437d JS: Fix observed FPs in UnsafeJQueryPlugin 2023-04-17 08:20:18 +02:00
Asger F
b321151a28 JS: Restrict ExtendCall flow in proto pollution query 2023-04-17 08:20:18 +02:00
Asger F
efb582b661 JS: Drive-by fix to newly gained FPs 2023-04-17 08:20:18 +02:00
Asger F
869c6d27fe JS: Add implied receiver steps 2023-04-17 08:20:18 +02:00
Asger F
74dbc71535 JS: Change Extend steps to PreCallGraphStep 2023-04-17 08:20:18 +02:00
Jami Cogswell
06bf246afe QL: update regexes 2023-04-16 16:10:23 -04:00
Geoffrey White
d94ed1b4a3 Merge pull request #12824 from geoffw0/modernsec4
Swift: Add CryptoSwift sinks in swift/weak-sensitive-data-hashing
2023-04-14 19:56:37 +01:00
Edward Minnix III
38826c98f1 Merge pull request #12751 from egregius313/egregius313/dataflow-refactor-cleanup
Java: Finish dataflow refactor
2023-04-14 10:35:11 -04:00
Geoffrey White
ba982e2f85 Merge pull request #12752 from gsingh93/buffer-access-array-expr
C++: Consider ArrayExpr with non-constant size expressions as a BufferAccess
2023-04-14 15:31:20 +01:00
Michael Nebel
4bca9511cd Merge pull request #12803 from michaelnebel/csharp/refactordataflow3
C#: Re-factor dataflow queries to use the new API.
2023-04-14 16:30:55 +02:00
Geoffrey White
9ecba6a94d Swift: Add missing imports in ExternalFlow.qll. 2023-04-14 14:58:24 +01:00
Geoffrey White
619d572d50 Swift: Add RNCryptor hmacKey encryption-key sinks. 2023-04-14 14:58:15 +01:00
Geoffrey White
46da73cc11 Swift: Add realm path-injection sinks. 2023-04-14 14:50:50 +01:00
Geoffrey White
feccd307da Swift: Add realm encryption-key sinks. 2023-04-14 14:47:24 +01:00
Geoffrey White
bfdaf6951d Swift: Add some test cases. 2023-04-14 14:39:45 +01:00
Geoffrey White
21414089ee Swift: Test renaming and layout changes. 2023-04-14 14:39:32 +01:00
Owen Mansel-Chan
8a4ca7fb84 Merge pull request #10026 from pwntester/patch-2
Go: Partial URLs should not sanitize against SSRF
2023-04-14 13:52:11 +01:00
Erik Krogh Kristensen
cece307c60 Merge pull request #12802 from erik-krogh/history-xss
JS: add browser history as XSS sink
2023-04-14 13:35:19 +02:00
Asger F
f4e8656c17 Ruby: move internal methods to API::Node::Internal 2023-04-14 13:35:13 +02:00
Owen Mansel-Chan
352866b52d Add change note 2023-04-14 12:00:38 +01:00
Owen Mansel-Chan
a42dbc5bab Fix formatting again 2023-04-14 12:00:38 +01:00
Owen Mansel-Chan
d407a689fa Fix formatting by deleting spaces no blank line 2023-04-14 12:00:38 +01:00
Owen Mansel-Chan
169bde8671 Fix formatting by deleting blank line 2023-04-14 12:00:38 +01:00
Alvaro Muñoz
8bf4b55309 Partial URLs should not sanitize against SSRF
As an example:

```go
	urlPath := ctx.Req.URL.Path
	hash := urlPath[strings.LastIndex(urlPath, "/")+1:]
        req, _ := http.NewRequest("GET", source+hash, nil)
```
2023-04-14 12:00:38 +01:00
Tony Torralba
f106783c39 SensitiveResultReceiverFlow needs to be public 2023-04-14 09:04:56 +02:00
Ed Minnix
7b56383b52 Make SensitiveResultReceiver modules private 2023-04-13 23:08:46 -04:00
Ed Minnix
0a26916245 Re-Add SensitiveResultReceiverConf as deprecated 2023-04-13 23:06:16 -04:00
Edward Minnix III
77b67cbf2e Fix typo
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2023-04-13 23:06:16 -04:00
Ed Minnix
0fc775027f Fix SensitiveResultReceiver test case 2023-04-13 23:06:16 -04:00
Ed Minnix
3826b9be6c Re-add allowImplicitRead 2023-04-13 23:06:16 -04:00
Ed Minnix
74b71ff7e3 Replace allowImplicitRead with default implementation 2023-04-13 23:06:16 -04:00
Ed Minnix
ea54ea47b1 Deprecate sensitiveResultReceiver 2023-04-13 23:06:16 -04:00
Edward Minnix III
3e55c47e3e flow(_, sink) to flowTo(sink)
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2023-04-13 23:06:16 -04:00
Ed Minnix
5ed1868324 Refactor ratpack framework test 2023-04-13 23:06:16 -04:00
Ed Minnix
88eb0231c1 Refactor taintedString.ql test 2023-04-13 23:06:16 -04:00
Ed Minnix
cd661f1d9f Refactor SensitiveResultReceiver 2023-04-13 23:06:16 -04:00
Ed Minnix
735a7383c6 Refactor HardcodedCredentialsSourceCall 2023-04-13 23:06:16 -04:00
Jami Cogswell
1b1838b5a8 Java: update Netty test case 2023-04-13 11:29:47 -04:00
Robert Marsh
fddbffee6f C++: autoformat 2023-04-13 11:13:27 -04:00
Jami Cogswell
4f9c51a02b Java: update provenance to hq-manual now that 12595 is merged 2023-04-13 10:11:31 -04:00
Robert Marsh
316cb95547 C++: respond to overflow PR comments 2023-04-13 10:03:55 -04:00
Jami Cogswell
0e3d9e1fec Java: update options file 2023-04-13 09:57:44 -04:00
Jami Cogswell
8a756eced9 Java: add combined manual and generated stubs directory back 2023-04-13 09:54:14 -04:00
Jami Cogswell
f0749f69c7 Java: remove manual-only stub directory 2023-04-13 09:52:29 -04:00
Mathias Vorreiter Pedersen
0db05fe4fa C++: Use the new dataflow library in the 'missing scanf' query. 2023-04-13 14:51:08 +01:00
Jami Cogswell
544997d42f Java: remove generated-only stub directory 2023-04-13 09:50:22 -04:00
Jami Cogswell
523feabaa2 Java: switch Netty setUri method from summary to sink; resolve conflicts 2023-04-13 09:16:18 -04:00
Michael Nebel
e648c643ca C#: Re-factor ExceptionInformationExposure to use the new API. 2023-04-13 15:15:58 +02:00
Jami Cogswell
0ffe9ab8d5 Java: add generated stubs back, but in a different directory from existing apache-http-5 stubs 2023-04-13 09:15:03 -04:00
Jami Cogswell
f27eff4f73 Java: add tests back 2023-04-13 09:15:03 -04:00
Jami Cogswell
8aabd28461 Java: temp add old stubs back 2023-04-13 09:15:02 -04:00
Jami Cogswell
fde855b25f Java: temp removal of stubs 2023-04-13 09:15:02 -04:00
Jami Cogswell
6271b6f1c3 Java: temp removal of tests 2023-04-13 09:15:02 -04:00
Jami Cogswell
7fb8819a08 Java: fix generated stub causing lang test failure 2023-04-13 09:15:02 -04:00
Jami Cogswell
0445509080 Java: update test cases and add stubs 2023-04-13 09:15:02 -04:00
Jami Cogswell
6890434d63 Java: add change note 2023-04-13 09:15:02 -04:00
Jami Cogswell
d85bcacf84 Java: update some models, undo temp edits; resolve conflicts 2023-04-13 09:14:52 -04:00
Jami Cogswell
540b8391dc Java: add more tests 2023-04-13 09:12:55 -04:00
Jami Cogswell
99320857af Java: change model to summary and update comments 2023-04-13 09:12:55 -04:00
Jami Cogswell
8a6ff95035 Java: remove neutral which will be added in a different PR 2023-04-13 09:12:54 -04:00
Jami Cogswell
4daaf783e1 Java: remove cache ones for now 2023-04-13 09:12:54 -04:00
Jami Cogswell
cd7b79f62b Java: add tests for org.apache.hc.client5.http.fluent 2023-04-13 09:12:54 -04:00
Jami Cogswell
1afa5af3dd Java: move version 5 tests to new file and add tests for org.apache.hc.client5.http.classic.methods 2023-04-13 09:12:54 -04:00
Jami Cogswell
a9595647c4 Java: fix typo 2023-04-13 09:12:54 -04:00
Jami Cogswell
33afcd75f1 Java: add subtype-related comments, update some empty-string signatures 2023-04-13 09:12:54 -04:00
Jami Cogswell
2a23f8766e Java: add tests for org.apache.hc.client5.http.async.methods.model.yml; resolve conflicts 2023-04-13 09:12:54 -04:00
Jami Cogswell
e89df255e3 Java: add subtype-related comments on org.apache.hc.client5.http.async.methods models 2023-04-13 09:12:54 -04:00
Jami Cogswell
4ab184fc7d Java: switch HttpHost from sink to summary; resolve conflicts 2023-04-13 09:12:54 -04:00
Jami Cogswell
4ed101fa26 Java: remove some comments 2023-04-13 09:12:54 -04:00
Jami Cogswell
a991f87728 Java: add some host sinks 2023-04-13 09:12:54 -04:00
Jami Cogswell
68fe486c05 Java: remove typo FP, boolean arg is not a sink 2023-04-13 09:12:54 -04:00
Jami Cogswell
60dab3d779 Java: add models from client version 4; resolve conflicts 2023-04-13 09:12:42 -04:00
Jami Cogswell
68391acc98 Java: add models from core version 4; resolve conflict 2023-04-13 09:06:28 -04:00
Jami Cogswell
de4cfc3239 Java: remove typo sink, this api is covered by the model for org.apache.http.client.methods.HttpRequestBase.setURI instead 2023-04-13 09:06:28 -04:00
Jami Cogswell
a3976305ca Java: add initial ssrf heuristic models for apache httpcomponents version 5 2023-04-13 09:06:28 -04:00
Michael Nebel
bb75ed03da C#: Re-factor ExposureInTransmittedData to use the new API. 2023-04-13 15:05:25 +02:00
Michael Nebel
f4ee1a5119 C#: Re-factor UncontrolledFormatString to use the new API. 2023-04-13 15:01:06 +02:00
Michael Nebel
9a62f51694 C#: Re-factor AssemblyPathInjection to use the new API. 2023-04-13 14:54:25 +02:00
Michael Nebel
ca029f5718 C#: Re-factor XMLInjection to use the new API. 2023-04-13 14:50:51 +02:00
Michael Nebel
5601ad64ef C#: Re-factor UnsafeYearConstruction to use the new API. 2023-04-13 14:42:03 +02:00
Michael Nebel
eb7e401aea C#: Re-factor ThreadUnsafeICryptoTransformLambda to use the new API. 2023-04-13 14:36:52 +02:00
Michael Nebel
e3cbebae30 C#: Re-factor ProcessNameToHashTaintFlow to use the new API. 2023-04-13 14:28:27 +02:00
Michael Nebel
96f9c40fdb C#: Re-factor TaintedWebClient to use the new API. 2023-04-13 14:28:27 +02:00
Michael Nebel
a96ad600fc C#: Re-factor ZipSlip to use the new API. 2023-04-13 14:28:27 +02:00
Michael Nebel
3e4e75cee8 C#: Re-factor XPathInjection to use the new API. 2023-04-13 14:28:27 +02:00
Michael Nebel
e6be88b10e C#: Re-factor XmlEntityInjection to use the new API. 2023-04-13 14:28:27 +02:00
Michael Nebel
60544c6889 C#: Re-factor UrlRedirect to use the new API. 2023-04-13 14:28:27 +02:00
Michael Nebel
bdf1da340d C#: Re-factor TaintedPath to use the new API. 2023-04-13 14:28:27 +02:00
Mathias Vorreiter Pedersen
f9d5e56d9c s/entry/exit 2023-04-13 13:22:07 +01:00
Mathias Vorreiter Pedersen
f32d77b36c Swift: Add QLDoc. 2023-04-13 13:13:18 +01:00
Mathias Vorreiter Pedersen
68cdc3b48e Swift: Accept test changes. 2023-04-13 13:13:15 +01:00
Mathias Vorreiter Pedersen
33bc7eabbb Swift: Fix CFG for key-path expressions. 2023-04-13 13:12:09 +01:00
Mathias Vorreiter Pedersen
859b3051b7 Swift: Add consistency queries to CFG tests. 2023-04-13 13:12:02 +01:00
Mathias Vorreiter Pedersen
b2d4a82932 C++: Fix annotations. 2023-04-13 11:13:15 +01:00
Mathias Vorreiter Pedersen
1ac5db3a98 C++: Fix annotations. 2023-04-13 11:07:12 +01:00
Mathias Vorreiter Pedersen
31b71ea163 C++: Fix annotations. 2023-04-13 11:04:51 +01:00
Mathias Vorreiter Pedersen
40dde93beb C++: Fix FP and accept test changes. 2023-04-13 11:00:08 +01:00
Mathias Vorreiter Pedersen
23a7cd943f C++: Fix missing result and accept test changes. 2023-04-13 10:50:46 +01:00
Mathias Vorreiter Pedersen
416f8d5ac9 C++: Fix test annotations. 2023-04-13 10:47:17 +01:00
Mathias Vorreiter Pedersen
c76dbebd9b C++: Ensure that the 'use-after-free' query is run on 'test_free.cpp'. 2023-04-13 10:47:07 +01:00
Tom Hvitved
3cc9dec9c8 Remove all queries.xml files 2023-04-13 11:18:58 +02:00
Mathias Vorreiter Pedersen
d304022685 C++: Add QLDoc to 'isExcludeFreePair'. 2023-04-13 10:15:23 +01:00
Arthur Baars
ead8108aed Apply suggestions from code review
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2023-04-13 11:11:55 +02:00
Mathias Vorreiter Pedersen
e0aeea058e C++: Fix qhelp for double-free. 2023-04-13 10:10:42 +01:00
Mathias Vorreiter Pedersen
184cb74cd0 Swift: Accept test changes. 2023-04-12 17:38:34 +01:00
Mathias Vorreiter Pedersen
f46ea325e8 Swift: Add dataflow through key-path expressios by modeling them as lambdas that perform a sequence of read steps. 2023-04-12 17:38:34 +01:00
Mathias Vorreiter Pedersen
21b03927c5 Swift: Add failing tests. 2023-04-12 17:38:29 +01:00
Mathias Vorreiter Pedersen
ba4e3ae949 Update cpp/ql/src/Critical/FlowAfterFree.qll
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
2023-04-12 16:50:57 +01:00
Mathew Payne
824ff8ad88 Add function signature to model 2023-04-12 14:54:06 +00:00
Mathew Payne
ffec22a5d2 Add change log notes 2023-04-12 14:48:28 +00:00
Mathew Payne
d0529bba2b Add missing models for Java IO
- java.io.OutputStream
- java.nio.file.Files
2023-04-12 14:43:11 +00:00
Asger F
69cb138912 Ruby: Tweak caching/inlining or API graph predicates 2023-04-12 15:56:58 +02:00
Asger F
7e23bf3938 Ruby: remove some redundant getASubclass() calls 2023-04-12 15:32:01 +02:00
erik-krogh
b1957623c1 add browser history as XSS sink 2023-04-12 13:38:18 +02:00
Mathias Vorreiter Pedersen
ab70f5722e C++: More QLDoc. 2023-04-12 11:22:31 +01:00
Mathias Vorreiter Pedersen
49cceb2901 C++: Fix joins. 2023-04-12 09:58:24 +01:00
Geoffrey White
cdcee5cc75 Swift: Add high-level CryptoSwift sinks. 2023-04-11 19:59:43 +01:00
Geoffrey White
539f8f0f70 Swift: Add mid-level CryptoSwift sinks and prevent duplication that results. Overall this doesn't give us any new results in tests, but makes paths shorter, and in the real world I expect it to add reliability. 2023-04-11 19:54:55 +01:00
Geoffrey White
51a62b54ee Swift: Add low-level CryptoSwift sinks. 2023-04-11 19:54:48 +01:00
Geoffrey White
d299d92025 Swift: Prevent potentially misleading duplicate results. 2023-04-11 19:39:09 +01:00
Geoffrey White
4995f13234 Swift: Add tests for swift/weak-sensitive-data-hashing on CryptoSwift. 2023-04-11 18:46:38 +01:00
Arthur Baars
83cd55cb29 Js/Yaml: add getFile() predicate 2023-04-11 16:01:44 +01:00
Robert Marsh
18c3feb9d8 C++: remove commented-out code
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2023-04-11 10:41:18 -04:00
Mathias Vorreiter Pedersen
259d5b6452 C++: Add use-after-free change note. 2023-04-11 15:30:51 +01:00
Mathias Vorreiter Pedersen
c1960c6ff9 C++: Add double-free change note. 2023-04-11 15:30:51 +01:00
Mathias Vorreiter Pedersen
3c88590df2 C++: Accept test changes for the new use-after-query. 2023-04-11 15:21:21 +01:00
Mathias Vorreiter Pedersen
725004a6fe C++: Modernize use-after-free query using dataflow. 2023-04-11 15:21:21 +01:00
Mathias Vorreiter Pedersen
17fe5f2317 C++: Change the id of the experimental double-free query to not overlap with the new non-experimental one. 2023-04-11 15:21:21 +01:00
Mathias Vorreiter Pedersen
a8151b4ee4 C++: Add double-free tests. 2023-04-11 15:21:21 +01:00
Mathias Vorreiter Pedersen
fb2ec15dad C++: Add double-free query documentation. 2023-04-11 15:21:21 +01:00
Mathias Vorreiter Pedersen
cc12e74c23 C++: Add double-free query. 2023-04-11 14:44:15 +01:00
Mathias Vorreiter Pedersen
dfe00ffe4b C++: Add a flow-after-free library. 2023-04-11 14:40:17 +01:00
erik-krogh
3c4bd5b6a7 forward toString() etc. predicates from YamlNode to Locatable 2023-04-11 15:37:01 +02:00
erik-krogh
b5e90483f5 improve the ESLint model to avoid overriding Yaml classes 2023-04-11 15:36:18 +02:00
Mathias Vorreiter Pedersen
d65bb3b232 C++: Make basic block information available from dataflow nodes. 2023-04-11 13:52:26 +01:00
Nate Johnson
a0f4a5100f Insecure HTTP parser query for JavaScript 2023-04-09 20:38:55 -04:00
Harry Maclean
8691845d23 Ruby: Re-add test
This got lost in an earlier refactor.
2023-04-07 15:50:48 +08:00
Harry Maclean
2ef6d5c7b9 Ruby/QL: Remove unnecessary CLI config 2023-04-07 15:49:17 +08:00
Harry Maclean
d942b54a9d Ruby: Update scripts for merged extractor 2023-04-07 15:49:17 +08:00
Harry Maclean
c13999100b QL: Update scripts for merged extractor 2023-04-07 15:49:17 +08:00
Harry Maclean
eff4729577 QL: Merge extractor binaries into one
There is now one binary, codeql-ql-extractor, which takes a positional
argument specifying whether to extract, generate or autobuild.
2023-04-07 15:49:16 +08:00
Harry Maclean
e4b4d8a3cd QL: Enable derive feature in clap
This allows nicer CLI definitions.
2023-04-07 12:04:02 +08:00
Harry Maclean
79089b40b9 Ruby: Merge extractor binaries into one
There is now one binary, codeql-ruby-extractor, which takes a positional
argument specifying whether to extract, generate or autobuild.
2023-04-07 12:04:02 +08:00
Harry Maclean
5a8a6f2971 Ruby: Enable derive feature in clap
This allows nicer CLI definitions.
2023-04-07 12:04:02 +08:00
Arthur Baars
4fca4b668c JS: use shared YAML library 2023-04-06 15:11:35 +02:00
Arthur Baars
f0b5f9c928 Shared YAML library 2023-04-06 15:11:35 +02:00
Paolo Tranquilli
acaa6a5ea7 Swift: make trap domain logger names more informative 2023-04-06 12:53:47 +02:00
Paolo Tranquilli
a5162b0b7d Swift: remove Log::configure 2023-04-06 12:53:13 +02:00
Robert Marsh
915c969efe Merge branch 'main' into rdmarsh2/range-analysis-overflow 2023-04-05 16:19:55 -04:00
Paolo Tranquilli
6ef9088076 Swift: rename LOG_IMPL->LOG_WITH_LEVEL and strengthen it 2023-04-05 06:30:49 +02:00
Robert Marsh
e4ae957cdd C++: More fixes to overflow detection 2023-04-04 09:31:03 -04:00
Paolo Tranquilli
5a01feca6c Swift: expand Logger doc comment 2023-04-04 10:37:59 +02:00
Paolo Tranquilli
6c932bc807 Swift: address logging review comments 2023-04-04 10:28:11 +02:00
Gulshan Singh
56dc2a4d4e C++: Consider ArrayExpr with non-constant size expressions as BufferAccesses 2023-04-03 23:11:14 -07:00
Paolo Tranquilli
abc0c7cf24 Swift: add trace logging of all trap emission 2023-04-03 11:47:24 +02:00
Paolo Tranquilli
a386c58371 Swift: add preliminary logging to dispatcher 2023-04-03 11:47:23 +02:00
Paolo Tranquilli
3fc488167f Swift: add logging to main 2023-04-03 11:47:23 +02:00
Paolo Tranquilli
ed48065c2d Swift: add logging infrastructure 2023-04-03 11:47:23 +02:00
Robert Marsh
2606abfc64 C++: sign analysis in potentiallyOverflowingExpr 2023-03-30 12:19:26 -04:00
Robert Marsh
868b2385d1 C++: fix SimpleRangeAnalysis for equivclass SemExpr 2023-03-30 12:19:25 -04:00
Robert Marsh
4b4fc97221 Merge branch 'main' into rdmarsh2/range-analysis-overflow 2023-03-30 11:45:55 -04:00
Robert Marsh
7ea74df4b3 C++: SimpleRangeAnalysis wrapper uses constant stage 2023-03-23 11:59:52 -04:00
Robert Marsh
204dbee14c C++: Move overflow detection to SimpleRangeAnalysis.qll 2023-03-21 11:02:06 -04:00
Robert Marsh
0f4157c534 C++: Add overflow detection to new range analysis 2023-03-21 11:01:58 -04:00
506 changed files with 15592 additions and 4018 deletions

View File

@@ -1 +1 @@
5.0.0
6.1.2

View File

@@ -15,7 +15,7 @@ jobs:
- name: Set up Go 1.20
uses: actions/setup-go@v4
with:
go-version: 1.20.0
go-version: '1.20'
id: go
- name: Check out code
@@ -50,7 +50,7 @@ jobs:
- name: Set up Go 1.20
uses: actions/setup-go@v4
with:
go-version: 1.20.0
go-version: '1.20'
id: go
- name: Check out code

View File

@@ -23,7 +23,7 @@ jobs:
- name: Set up Go 1.20
uses: actions/setup-go@v4
with:
go-version: 1.20.0
go-version: '1.20'
id: go
- name: Check out code

View File

@@ -58,10 +58,8 @@ jobs:
id: cache-extractor
with:
path: |
ruby/extractor/target/release/autobuilder
ruby/extractor/target/release/autobuilder.exe
ruby/extractor/target/release/extractor
ruby/extractor/target/release/extractor.exe
ruby/extractor/target/release/codeql-extractor-ruby
ruby/extractor/target/release/codeql-extractor-ruby.exe
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}--${{ hashFiles('ruby/extractor/**/*.rs') }}
- uses: actions/cache@v3
@@ -88,15 +86,13 @@ jobs:
run: |
cd extractor
cross build --release
mv target/x86_64-unknown-linux-gnu/release/extractor target/release/
mv target/x86_64-unknown-linux-gnu/release/autobuilder target/release/
mv target/x86_64-unknown-linux-gnu/release/generator target/release/
mv target/x86_64-unknown-linux-gnu/release/codeql-extractor-ruby target/release/
- name: Release build (windows and macos)
if: steps.cache-extractor.outputs.cache-hit != 'true' && runner.os != 'Linux'
run: cd extractor && cargo build --release
- name: Generate dbscheme
if: ${{ matrix.os == 'ubuntu-latest' && steps.cache-extractor.outputs.cache-hit != 'true'}}
run: extractor/target/release/generator --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
run: extractor/target/release/codeql-extractor-ruby generate --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
- uses: actions/upload-artifact@v3
if: ${{ matrix.os == 'ubuntu-latest' }}
with:
@@ -111,10 +107,8 @@ jobs:
with:
name: extractor-${{ matrix.os }}
path: |
ruby/extractor/target/release/autobuilder
ruby/extractor/target/release/autobuilder.exe
ruby/extractor/target/release/extractor
ruby/extractor/target/release/extractor.exe
ruby/extractor/target/release/codeql-extractor-ruby
ruby/extractor/target/release/codeql-extractor-ruby.exe
retention-days: 1
compile-queries:
runs-on: ubuntu-latest-xl
@@ -172,13 +166,10 @@ jobs:
mkdir -p ruby
cp -r codeql-extractor.yml tools ql/lib/ruby.dbscheme.stats ruby/
mkdir -p ruby/tools/{linux64,osx64,win64}
cp linux64/autobuilder ruby/tools/linux64/autobuilder
cp osx64/autobuilder ruby/tools/osx64/autobuilder
cp win64/autobuilder.exe ruby/tools/win64/autobuilder.exe
cp linux64/extractor ruby/tools/linux64/extractor
cp osx64/extractor ruby/tools/osx64/extractor
cp win64/extractor.exe ruby/tools/win64/extractor.exe
chmod +x ruby/tools/{linux64,osx64}/{autobuilder,extractor}
cp linux64/codeql-extractor-ruby ruby/tools/linux64/extractor
cp osx64/codeql-extractor-ruby ruby/tools/osx64/extractor
cp win64/codeql-extractor-ruby.exe ruby/tools/win64/extractor.exe
chmod +x ruby/tools/{linux64,osx64}/extractor
zip -rq codeql-ruby.zip ruby
- uses: actions/upload-artifact@v3
with:

View File

@@ -8,16 +8,16 @@ provide:
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
- "go/ql/config/legacy-support/qlpack.yml"
- "go/build/codeql-extractor-go/codeql-extractor.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml"
- "*/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml"
# This pack is explicitly excluded from the workspace since most users
# will want to use a version of this pack from the package cache. Internal
# users can uncomment the following line and place a custom ML model
# in the corresponding pack to test a custom ML model within their local
# checkout.
# - "javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
# - "*/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
- "*/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
- "*/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
- "*/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"

View File

@@ -1 +0,0 @@
<queries language="cpp"/>

View File

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

View File

@@ -65,6 +65,7 @@ class Location extends @location {
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
pragma[inline]
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {

View File

@@ -897,23 +897,6 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
}
}
/**
* Gets the basic block of `node`.
*/
IRBlock getBasicBlock(Node node) {
node.asInstruction().getBlock() = result
or
node.asOperand().getUse().getBlock() = result
or
node.(SsaPhiNode).getPhiNode().getBasicBlock() = result
or
node.(RawIndirectOperand).getOperand().getUse().getBlock() = result
or
node.(RawIndirectInstruction).getInstruction().getBlock() = result
or
result = getBasicBlock(node.(PostUpdateNode).getPreUpdateNode())
}
/**
* A local flow relation that includes both local steps, read steps and
* argument-to-return flow through summarized functions.
@@ -999,7 +982,8 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
// we pick the one with the highest edge count.
result =
max(SsaPhiNode phi |
switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() = getBasicBlock(phi) and
switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() =
phi.getBasicBlock() and
phi.getSourceVariable() = sv
|
strictcount(phi.getAnInput())

View File

@@ -160,6 +160,28 @@ class Node extends TIRDataFlowNode {
/** Gets the operands corresponding to this node, if any. */
Operand asOperand() { result = this.(OperandNode).getOperand() }
/**
* Holds if this node is at index `i` in basic block `block`.
*
* Note: Phi nodes are considered to be at index `-1`.
*/
final predicate hasIndexInBlock(IRBlock block, int i) {
this.asInstruction() = block.getInstruction(i)
or
this.asOperand().getUse() = block.getInstruction(i)
or
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
or
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
or
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
or
this.(PostUpdateNode).getPreUpdateNode().hasIndexInBlock(block, i)
}
/** Gets the basic block of this node, if any. */
final IRBlock getBasicBlock() { this.hasIndexInBlock(result, _) }
/**
* Gets the non-conversion expression corresponding to this node, if any.
* This predicate only has a result on nodes that represent the value of
@@ -530,7 +552,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
*/
final Node getAnInput(boolean fromBackEdge) {
localFlowStep(result, this) and
if phi.getBasicBlock().dominates(getBasicBlock(result))
if phi.getBasicBlock().dominates(result.getBasicBlock())
then fromBackEdge = true
else fromBackEdge = false
}
@@ -1887,7 +1909,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
e = value.getAnInstruction().getConvertedResultExpression() and
result.getConvertedExpr() = e and
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
g.controls(getBasicBlock(result), edge)
g.controls(result.getBasicBlock(), edge)
)
}
}

View File

@@ -26,12 +26,17 @@ predicate ignoreOperand(Operand operand) {
predicate ignoreInstruction(Instruction instr) {
DataFlowImplCommon::forceCachingInSameStage() and
(
instr instanceof CallSideEffectInstruction or
instr instanceof CallReadSideEffectInstruction or
instr instanceof ExitFunctionInstruction or
instr instanceof EnterFunctionInstruction or
instr instanceof WriteSideEffectInstruction or
instr instanceof PhiInstruction or
instr instanceof ReadSideEffectInstruction or
instr instanceof ChiInstruction or
instr instanceof InitializeIndirectionInstruction or
instr instanceof AliasedDefinitionInstruction or
instr instanceof AliasedUseInstruction or
instr instanceof InitializeNonLocalInstruction or
instr instanceof ReturnIndirectionInstruction
)

View File

@@ -8,6 +8,8 @@ private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
/**
* Gets the lower bound of the expression.
@@ -22,8 +24,10 @@ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Rang
* `lowerBound(expr.getFullyConverted())`
*/
float lowerBound(Expr expr) {
exists(Instruction i, SemBound b | i.getAst() = expr and b instanceof SemZeroBound |
semBounded(getSemanticExpr(i), b, result, false, _)
exists(Instruction i, ConstantBounds::SemBound b |
i.getAst() = expr and b instanceof ConstantBounds::SemZeroBound
|
ConstantStage::semBounded(getSemanticExpr(i), b, result, false, _)
)
}
@@ -40,8 +44,10 @@ float lowerBound(Expr expr) {
* `upperBound(expr.getFullyConverted())`
*/
float upperBound(Expr expr) {
exists(Instruction i, SemBound b | i.getAst() = expr and b instanceof SemZeroBound |
semBounded(getSemanticExpr(i), b, result, true, _)
exists(Instruction i, ConstantBounds::SemBound b |
i.getAst() = expr and b instanceof ConstantBounds::SemZeroBound
|
ConstantStage::semBounded(getSemanticExpr(i), b, result, true, _)
)
}
@@ -90,7 +96,15 @@ predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) {
* does not consider the possibility that the expression might overflow
* due to a conversion.
*/
predicate exprMightOverflowNegatively(Expr expr) { none() }
predicate exprMightOverflowNegatively(Expr expr) {
lowerBound(expr) < exprMinVal(expr)
or
exists(SemanticExprConfig::Expr semExpr |
semExpr.getUnconverted().getAst() = expr and
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
)
}
/**
* Holds if the expression might overflow negatively. Conversions
@@ -108,7 +122,15 @@ predicate convertedExprMightOverflowNegatively(Expr expr) {
* does not consider the possibility that the expression might overflow
* due to a conversion.
*/
predicate exprMightOverflowPositively(Expr expr) { none() }
predicate exprMightOverflowPositively(Expr expr) {
upperBound(expr) > exprMaxVal(expr)
or
exists(SemanticExprConfig::Expr semExpr |
semExpr.getUnconverted().getAst() = expr and
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
)
}
/**
* Holds if the expression might overflow positively. Conversions

View File

@@ -1,4 +1,5 @@
private import RangeAnalysisStage
private import RangeAnalysisImpl
module FloatDelta implements DeltaSig {
class Delta = float;
@@ -18,3 +19,36 @@ module FloatDelta implements DeltaSig {
bindingset[f]
Delta fromFloat(float f) { result = f }
}
module FloatOverflow implements OverflowSig<FloatDelta> {
predicate semExprDoesNotOverflow(boolean positively, SemExpr expr) {
exists(float lb, float ub, float delta |
typeBounds(expr.getSemType(), lb, ub) and
ConstantStage::initialBounded(expr, any(ConstantBounds::SemZeroBound b), delta, positively, _,
_, _)
|
positively = true and delta < ub
or
positively = false and delta > lb
)
}
additional predicate typeBounds(SemType t, float lb, float ub) {
exists(SemIntegerType integralType, float limit |
integralType = t and limit = 2.pow(8 * integralType.getByteSize())
|
if integralType instanceof SemBooleanType
then lb = 0 and ub = 1
else
if integralType.isSigned()
then (
lb = -(limit / 2) and ub = (limit / 2) - 1
) else (
lb = 0 and ub = limit - 1
)
)
or
// This covers all floating point types. The range is (-Inf, +Inf).
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
}
}

View File

@@ -1,2 +1,3 @@
import RangeAnalysisImpl
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
private import RangeAnalysisImpl as Impl
import Impl::Public

View File

@@ -6,7 +6,7 @@ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import RangeAnalysisStage
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
module CppLangImpl implements LangSig<FloatDelta> {
module CppLangImplConstant implements LangSig<FloatDelta> {
/**
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
*

View File

@@ -1,5 +1,6 @@
private import RangeAnalysisStage
private import RangeAnalysisSpecific
private import RangeAnalysisConstantSpecific
private import RangeAnalysisRelativeSpecific
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
private import RangeUtils
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound as SemanticBound
@@ -28,7 +29,7 @@ module ConstantBounds implements BoundSig<FloatDelta> {
}
}
private module RelativeBounds implements BoundSig<FloatDelta> {
module RelativeBounds implements BoundSig<FloatDelta> {
class SemBound instanceof SemanticBound::SemBound {
SemBound() { not this instanceof SemanticBound::SemZeroBound }
@@ -46,11 +47,13 @@ private module RelativeBounds implements BoundSig<FloatDelta> {
}
}
private module ConstantStage =
RangeStage<FloatDelta, ConstantBounds, CppLangImpl, RangeUtil<FloatDelta, CppLangImpl>>;
module ConstantStage =
RangeStage<FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
RangeUtil<FloatDelta, CppLangImplConstant>>;
private module RelativeStage =
RangeStage<FloatDelta, RelativeBounds, CppLangImpl, RangeUtil<FloatDelta, CppLangImpl>>;
module RelativeStage =
RangeStage<FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
RangeUtil<FloatDelta, CppLangImplRelative>>;
private newtype TSemReason =
TSemNoReason() or
@@ -60,48 +63,52 @@ private newtype TSemReason =
guard = any(RelativeStage::SemCondReason reason).getCond()
}
/**
* A reason for an inferred bound. This can either be `CondReason` if the bound
* is due to a specific condition, or `NoReason` if the bound is inferred
* without going through a bounding condition.
*/
abstract class SemReason extends TSemReason {
/** Gets a textual representation of this reason. */
abstract string toString();
}
/**
* A reason for an inferred bound that indicates that the bound is inferred
* without going through a bounding condition.
*/
class SemNoReason extends SemReason, TSemNoReason {
override string toString() { result = "NoReason" }
}
/** A reason for an inferred bound pointing to a condition. */
class SemCondReason extends SemReason, TSemCondReason {
/** Gets the condition that is the reason for the bound. */
SemGuard getCond() { this = TSemCondReason(result) }
override string toString() { result = getCond().toString() }
}
private ConstantStage::SemReason constantReason(SemReason reason) {
ConstantStage::SemReason constantReason(SemReason reason) {
result instanceof ConstantStage::SemNoReason and reason instanceof SemNoReason
or
result.(ConstantStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
}
private RelativeStage::SemReason relativeReason(SemReason reason) {
RelativeStage::SemReason relativeReason(SemReason reason) {
result instanceof RelativeStage::SemNoReason and reason instanceof SemNoReason
or
result.(RelativeStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
}
predicate semBounded(
SemExpr e, SemanticBound::SemBound b, float delta, boolean upper, SemReason reason
) {
ConstantStage::semBounded(e, b, delta, upper, constantReason(reason))
or
RelativeStage::semBounded(e, b, delta, upper, relativeReason(reason))
import Public
module Public {
predicate semBounded(
SemExpr e, SemanticBound::SemBound b, float delta, boolean upper, SemReason reason
) {
ConstantStage::semBounded(e, b, delta, upper, constantReason(reason))
or
RelativeStage::semBounded(e, b, delta, upper, relativeReason(reason))
}
/**
* A reason for an inferred bound. This can either be `CondReason` if the bound
* is due to a specific condition, or `NoReason` if the bound is inferred
* without going through a bounding condition.
*/
abstract class SemReason extends TSemReason {
/** Gets a textual representation of this reason. */
abstract string toString();
}
/**
* A reason for an inferred bound that indicates that the bound is inferred
* without going through a bounding condition.
*/
class SemNoReason extends SemReason, TSemNoReason {
override string toString() { result = "NoReason" }
}
/** A reason for an inferred bound pointing to a condition. */
class SemCondReason extends SemReason, TSemCondReason {
/** Gets the condition that is the reason for the bound. */
SemGuard getCond() { this = TSemCondReason(result) }
override string toString() { result = getCond().toString() }
}
}

View File

@@ -0,0 +1,126 @@
/**
* C++-specific implementation of range analysis.
*/
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import RangeAnalysisStage
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.IntDelta
private import RangeAnalysisImpl
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
module CppLangImplRelative implements LangSig<FloatDelta> {
/**
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreSsaReadCopy(SemExpr e) { none() }
/**
* Ignore the bound on this expression.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreExprBound(SemExpr e) {
exists(boolean upper, float delta, ConstantBounds::SemZeroBound b, float lb, float ub |
ConstantStage::semBounded(e, b, delta, upper, _) and
typeBounds(e.getSemType(), lb, ub) and
(
upper = false and
delta < lb
or
upper = true and
delta > ub
)
)
}
private predicate typeBounds(SemType t, float lb, float ub) {
exists(SemIntegerType integralType, float limit |
integralType = t and limit = 2.pow(8 * integralType.getByteSize())
|
if integralType instanceof SemBooleanType
then lb = 0 and ub = 1
else
if integralType.isSigned()
then (
lb = -(limit / 2) and ub = (limit / 2) - 1
) else (
lb = 0 and ub = limit - 1
)
)
or
// This covers all floating point types. The range is (-Inf, +Inf).
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
}
/**
* Ignore any inferred zero lower bound on this expression.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreZeroLowerBound(SemExpr e) { none() }
/**
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
/**
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
/**
* Adds additional results to `ssaRead()` that are specific to Java.
*
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
* in exactly the same way as the old Java implementation. Once the new implementation matches the
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
* or not they come from a post-increment/decrement expression.
*/
SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
/**
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
*/
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
/**
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
*/
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
/**
* Holds if the value of `dest` is known to be `src + delta`.
*/
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified expression,
* if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateType(SemExpr e) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified source
* variable, if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
}

View File

@@ -73,6 +73,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticType
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticOpcode
private import ConstantAnalysis
private import Sign
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
/**
@@ -240,11 +241,19 @@ signature module BoundSig<DeltaSig D> {
}
}
module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<D> UtilParam> {
signature module OverflowSig<DeltaSig D> {
predicate semExprDoesNotOverflow(boolean positively, SemExpr expr);
}
module RangeStage<
DeltaSig D, BoundSig<D> Bounds, OverflowSig<D> OverflowParam, LangSig<D> LangParam,
UtilSig<D> UtilParam>
{
private import Bounds
private import LangParam
private import UtilParam
private import D
private import OverflowParam
/**
* An expression that does conversion, boxing, or unboxing
@@ -920,6 +929,81 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
}
predicate bounded(
SemExpr e, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, D::Delta origdelta,
SemReason reason
) {
initialBounded(e, b, delta, upper, fromBackEdge, origdelta, reason) and
(
semExprDoesNotOverflow(upper.booleanNot(), e)
or
not potentiallyOverflowingExpr(upper.booleanNot(), e)
or
exists(D::Delta otherDelta |
initialBounded(e, _, otherDelta, upper.booleanNot(), _, _, _) and
(
upper = true and D::toFloat(otherDelta) >= 0
or
upper = false and D::toFloat(otherDelta) <= 0
)
)
)
}
predicate potentiallyOverflowingExpr(boolean positively, SemExpr expr) {
(
expr.getOpcode() instanceof Opcode::Add or
expr.getOpcode() instanceof Opcode::PointerAdd
) and
(
positively = true and
(
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TPos() and
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TPos()
)
or
positively = false and
(
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TNeg() and
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TNeg()
)
)
or
(
expr.getOpcode() instanceof Opcode::Sub or
expr.getOpcode() instanceof Opcode::PointerSub
) and
(
positively = true and
(
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TPos() and
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TNeg()
)
or
positively = false and
(
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TNeg() and
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TPos()
)
)
or
positively in [true, false] and
(
expr.getOpcode() instanceof Opcode::Mul or
expr.getOpcode() instanceof Opcode::ShiftLeft
)
or
positively = false and
(
expr.getOpcode() instanceof Opcode::Negate or
expr.getOpcode() instanceof Opcode::SubOne or
expr.(SemDivExpr).getSemType() instanceof SemFloatingPointType
)
or
positively = true and
expr.getOpcode() instanceof Opcode::AddOne
}
/**
* Computes a normal form of `x` where -0.0 has changed to +0.0. This can be
* needed on the lesser side of a floating-point comparison or on both sides of
@@ -934,7 +1018,7 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
* - `upper = true` : `e <= b + delta`
* - `upper = false` : `e >= b + delta`
*/
private predicate bounded(
predicate initialBounded(
SemExpr e, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, D::Delta origdelta,
SemReason reason
) {

View File

@@ -3,7 +3,7 @@
*/
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import RangeAnalysisSpecific
private import RangeAnalysisRelativeSpecific
private import RangeAnalysisStage as Range
private import ConstantAnalysis

View File

@@ -314,9 +314,8 @@ class FreadBA extends BufferAccess {
* but not:
* &buffer[ix]
*/
class ArrayExprBA extends BufferAccess {
class ArrayExprBA extends BufferAccess, ArrayExpr {
ArrayExprBA() {
exists(this.(ArrayExpr).getArrayOffset().getValue().toInt()) and
not exists(AddressOfExpr aoe | aoe.getAChild() = this) and
// exclude accesses in macro implementation of `strcmp`,
// which are carefully controlled but can look dangerous.

View File

@@ -0,0 +1,10 @@
int* f() {
int *buff = malloc(SIZE*sizeof(int));
do_stuff(buff);
free(buff);
int *new_buffer = malloc(SIZE*sizeof(int));
free(buff); // BAD: If new_buffer is assigned the same address as buff,
// the memory allocator will free the new buffer memory region,
// leading to use-after-free problems and memory corruption.
return new_buffer;
}

View File

@@ -0,0 +1,33 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Deallocating memory more than once can lead to a double-free vulnerability. This can be exploited to
corrupt the allocator's internal data structures, which can lead to denial-of-service attacks by crashing
the program, or security vulnerabilities, by allowing an attacker to overwrite arbitrary memory locations.
</p>
</overview>
<recommendation>
<p>
Ensure that all execution paths deallocate the allocated memory at most once. If possible, reassign
the pointer to a null value after deallocating it. This will prevent double-free vulnerabilities since
most deallocation functions will perform a null-pointer check before attempting to deallocate the memory.
</p>
</recommendation>
<example><sample src="DoubleFree.cpp" />
</example>
<references>
<li>
OWASP:
<a href="https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory">Doubly freeing memory</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,49 @@
/**
* @name Potential double free
* @description Freeing a resource more than once can lead to undefined behavior and cause memory corruption.
* @kind path-problem
* @precision medium
* @id cpp/double-free
* @problem.severity warning
* @security-severity 9.3
* @tags reliability
* security
* external/cwe/cwe-415
*/
import cpp
import semmle.code.cpp.dataflow.new.DataFlow
import FlowAfterFree
import DoubleFree::PathGraph
predicate isFree(DataFlow::Node n, Expr e) { isFree(n, e, _) }
/**
* `dealloc1` is a deallocation expression and `e` is an expression such
* that is deallocated by a deallocation expression, and the `(dealloc1, e)` pair
* should be excluded by the `FlowFromFree` library.
*
* Note that `e` is not necessarily the expression deallocated by `dealloc1`. It will
* be bound to the second deallocation as identified by the `FlowFromFree` library.
*/
bindingset[dealloc1, e]
predicate isExcludeFreePair(DeallocationExpr dealloc1, Expr e) {
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
// to release the memory that was allocated for the MDL structure."
isExFreePoolCall(dealloc2, _)
)
}
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(sink.getNode(), e2)
select sink.getNode(), source, sink,
"Memory pointed to by '" + e2.toString() + "' may already have been freed by $@.", dealloc,
dealloc.toString()

View File

@@ -0,0 +1,129 @@
import cpp
import semmle.code.cpp.dataflow.new.DataFlow
private import semmle.code.cpp.ir.IR
/**
* Signature for a predicate that holds if `n.asExpr() = e` and `n` is a sink in
* the `FlowFromFreeConfig` module.
*/
private signature predicate isSinkSig(DataFlow::Node n, Expr e);
/**
* Holds if `dealloc` is a deallocation expression and `e` is an expression such
* that `isFree(_, e)` holds for some `isFree` predicate satisfying `isSinkSig`,
* and this source-sink pair should be excluded from the analysis.
*/
bindingset[dealloc, e]
private signature predicate isExcludedSig(DeallocationExpr dealloc, Expr e);
/**
* Holds if `(b1, i1)` strictly post-dominates `(b2, i2)`
*/
bindingset[i1, i2]
predicate strictlyPostDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
b1 = b2 and
i1 > i2
or
b1.strictlyPostDominates(b2)
}
/**
* Holds if `(b1, i1)` strictly dominates `(b2, i2)`
*/
bindingset[i1, i2]
predicate strictlyDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
b1 = b2 and
i1 < i2
or
b1.strictlyDominates(b2)
}
/**
* Constructs a `FlowFromFreeConfig` module that can be used to find flow between
* a pointer being freed by some deallocation function, and a user-specified sink.
*
* In order to reduce false positives, the set of sinks is restricted to only those
* that satisfy at least one of the following two criteria:
* 1. The source dominates the sink, or
* 2. The sink post-dominates the source.
*/
module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
module FlowFromFreeConfig implements DataFlow::StateConfigSig {
class FlowState instanceof Expr {
FlowState() { isFree(_, this, _) }
string toString() { result = super.toString() }
}
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, state, _) }
pragma[inline]
predicate isSink(DataFlow::Node sink, FlowState state) {
exists(
Expr e, DataFlow::Node source, IRBlock b1, int i1, IRBlock b2, int i2,
DeallocationExpr dealloc
|
isASink(sink, e) and
isFree(source, state, dealloc) and
e != state and
source.hasIndexInBlock(b1, i1) and
sink.hasIndexInBlock(b2, i2) and
not isExcluded(dealloc, e)
|
strictlyDominates(b1, i1, b2, i2)
or
strictlyPostDominates(b2, i2, b1, i1)
)
}
predicate isBarrierIn(DataFlow::Node n) {
n.asIndirectExpr() = any(AddressOfExpr aoe)
or
n.asIndirectExpr() = any(Call call).getAnArgument()
or
exists(Expr e |
n.asIndirectExpr() = e.(PointerDereferenceExpr).getOperand() or
n.asIndirectExpr() = e.(ArrayExpr).getArrayBase()
|
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
)
}
predicate isBarrier(DataFlow::Node n, FlowState state) { none() }
predicate isAdditionalFlowStep(
DataFlow::Node n1, FlowState state1, DataFlow::Node n2, FlowState state2
) {
none()
}
}
import DataFlow::GlobalWithState<FlowFromFreeConfig>
}
/**
* Holds if `n` is a dataflow node such that `n.asExpr() = e` and `e`
* is being freed by a deallocation expression `dealloc`.
*/
predicate isFree(DataFlow::Node n, Expr e, DeallocationExpr dealloc) {
e = dealloc.getFreedExpr() and
e = n.asExpr() and
// Ignore realloc functions
not exists(dealloc.(FunctionCall).getTarget().(AllocationFunction).getReallocPtrArg())
}
/**
* Holds if `fc` is a function call that is the result of expanding
* the `ExFreePool` macro.
*/
predicate isExFreePoolCall(FunctionCall fc, Expr e) {
e = fc.getArgument(0) and
(
exists(MacroInvocation mi |
mi.getMacroName() = "ExFreePool" and
mi.getExpr() = fc
)
or
fc.getTarget().hasGlobalName("ExFreePool")
)
}

View File

@@ -16,160 +16,133 @@
import cpp
import semmle.code.cpp.commons.Scanf
import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.dataflow.new.DataFlow::DataFlow
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.ValueNumbering
/**
* Holds if `call` is a `scanf`-like function that may write to `output` at index `index`.
*
* Furthermore, `instr` is the instruction that defines the address of the `index`'th argument
* of `call`, and `vn` is the value number of `instr.`
*/
predicate isSource(ScanfFunctionCall call, int index, Instruction instr, ValueNumber vn, Expr output) {
output = call.getOutputArgument(index).getFullyConverted() and
instr.getConvertedResultExpression() = output and
vn.getAnInstruction() = instr
/** Holds if `n` reaches an argument to a call to a `scanf`-like function. */
pragma[nomagic]
predicate revFlow0(Node n) {
isSink(_, _, n, _)
or
exists(Node succ | revFlow0(succ) | localFlowStep(n, succ))
}
/**
* Holds if `instr` is control-flow reachable in 0 or more steps from
* a call to a `scanf`-like function.
* Holds if `n` represents an uninitialized stack-allocated variable, or a
* newly (and presumed uninitialized) heap allocation.
*/
predicate isUninitialized(Node n) {
exists(n.asUninitialized()) or
n.asIndirectExpr(1) instanceof AllocationExpr
}
pragma[nomagic]
predicate fwdFlow0(Instruction instr) {
isSource(_, _, instr, _, _)
or
exists(Instruction prev |
fwdFlow0(prev) and
prev.getASuccessor() = instr
predicate fwdFlow0(Node n) {
revFlow0(n) and
(
isUninitialized(n)
or
exists(Node prev |
fwdFlow0(prev) and
localFlowStep(prev, n)
)
)
}
/**
* Holds if `instr` is part of the IR translation of `access` that
* is not an expression being deallocated, and `instr` has value
* number `vn`.
*/
predicate isSink(Instruction instr, Access access, ValueNumber vn) {
instr.getAst() = access and
not any(DeallocationExpr dealloc).getFreedExpr() = access and
vn.getAnInstruction() = instr
predicate isSink(ScanfFunctionCall call, int index, Node n, Expr input) {
input = call.getOutputArgument(index) and
n.asIndirectExpr() = input
}
/**
* Holds if `instr` is part of a path from a call to a `scanf`-like function
* Holds if `call` is a `scanf`-like call and `output` is the `index`'th
* 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))
}
/**
* Holds if `call` is a `scanf`-like function that may write to `output` at
* index `index` and `n` is the dataflow node that represents the data after
* it has been written to by `call`.
*/
predicate isSource(ScanfFunctionCall call, int index, Node n, Expr output) {
isRelevantScanfCall(call, index, output) and
output = call.getOutputArgument(index) and
n.asDefiningArgument() = output
}
/**
* Holds if `n` is reachable from an output argument of a relevant call to
* a `scanf`-like function.
*/
pragma[nomagic]
predicate fwdFlow(Node n) {
isSource(_, _, n, _)
or
exists(Node prev |
fwdFlow(prev) and
localFlowStep(prev, n) and
not isSanitizerOut(prev)
)
}
/** Holds if `n` should not have outgoing flow. */
predicate isSanitizerOut(Node n) {
// We disable flow out of sinks to reduce result duplication
isSink(n, _)
or
// If the node is being passed to a function it may be
// modified, and thus it's safe to later read the value.
exists(n.asIndirectArgument())
}
/**
* Holds if `n` is a node such that `n.asExpr() = e` and `e` is not an
* argument of a deallocation expression.
*/
predicate isSink(Node n, Expr e) {
n.asExpr() = e and
not any(DeallocationExpr dealloc).getFreedExpr() = e
}
/**
* Holds if `n` is part of a path from a call to a `scanf`-like function
* to a use of the written variable.
*/
pragma[nomagic]
predicate revFlow0(Instruction instr) {
fwdFlow0(instr) and
predicate revFlow(Node n) {
fwdFlow(n) and
(
isSink(instr, _, _)
isSink(n, _)
or
exists(Instruction succ | revFlow0(succ) | instr.getASuccessor() = succ)
)
}
/**
* Holds if `instr` is part of a path from a call to a `scanf`-like function
* that writes to a variable with value number `vn`, without passing through
* redefinitions of the variable.
*/
pragma[nomagic]
private predicate fwdFlow(Instruction instr, ValueNumber vn) {
revFlow0(instr) and
(
isSource(_, _, instr, vn, _)
or
exists(Instruction prev |
fwdFlow(prev, vn) and
prev.getASuccessor() = instr and
not isBarrier(instr, vn)
exists(Node succ |
revFlow(succ) and
localFlowStep(n, succ) and
not isSanitizerOut(n)
)
)
}
/**
* Holds if `instr` is part of a path from a call to a `scanf`-like function
* that writes to a variable with value number `vn`, without passing through
* redefinitions of the variable.
*
* Note: This predicate only holds for the `(intr, vn)` pairs that are also
* control-flow reachable from an argument to a `scanf`-like function call.
*/
pragma[nomagic]
predicate revFlow(Instruction instr, ValueNumber vn) {
fwdFlow(instr, pragma[only_bind_out](vn)) and
(
isSink(instr, _, vn)
or
exists(Instruction succ | revFlow(succ, vn) |
instr.getASuccessor() = succ and
not isBarrier(succ, vn)
)
)
/** A local flow step, restricted to relevant dataflow nodes. */
private predicate step(Node n1, Node n2) {
revFlow(n1) and
revFlow(n2) and
localFlowStep(n1, n2)
}
/**
* A type that bundles together a reachable instruction with the appropriate
* value number (i.e., the value number that's transferred from the source
* to the sink).
*/
newtype TNode = MkNode(Instruction instr, ValueNumber vn) { revFlow(instr, vn) }
class Node extends MkNode {
ValueNumber vn;
Instruction instr;
Node() { this = MkNode(instr, vn) }
final string toString() { result = instr.toString() }
final Node getASuccessor() { result = MkNode(pragma[only_bind_out](instr.getASuccessor()), vn) }
final Location getLocation() { result = instr.getLocation() }
}
/**
* Holds if `instr` is an instruction with value number `vn` that is
* used in a store operation, or is overwritten by another call to
* a `scanf`-like function.
*/
private predicate isBarrier(Instruction instr, ValueNumber vn) {
// We only need to compute barriers for instructions that we
// managed to hit during the initial flow stage.
revFlow0(pragma[only_bind_into](instr)) and
valueNumber(instr) = vn and
exists(Expr e | instr.getAst() = e |
instr = any(StoreInstruction s).getDestinationAddress()
or
isSource(_, _, _, _, [e, e.getParent().(AddressOfExpr)])
)
}
/** Holds if `n1` steps to `n2` in a single step. */
predicate isSuccessor(Node n1, Node n2) { n1.getASuccessor() = n2 }
predicate hasFlow(Node n1, Node n2) = fastTC(isSuccessor/2)(n1, n2)
Node getNode(Instruction instr, ValueNumber vn) { result = MkNode(instr, vn) }
predicate hasFlow(Node n1, Node n2) = fastTC(step/2)(n1, n2)
/**
* Holds if `source` is the `index`'th argument to the `scanf`-like call `call`, and `sink` is
* an instruction that is part of the translation of `access` which is a transitive
* control-flow successor of `call`.
*
* Furthermore, `source` and `sink` have identical global value numbers.
* a dataflow node that represents the expression `e`.
*/
predicate hasFlow(
Instruction source, ScanfFunctionCall call, int index, Instruction sink, Access access
) {
exists(ValueNumber vn |
isSource(call, index, source, vn, _) and
hasFlow(getNode(source, pragma[only_bind_into](vn)), getNode(sink, pragma[only_bind_into](vn))) and
isSink(sink, access, vn)
)
predicate hasFlow(Node source, ScanfFunctionCall call, int index, Node sink, Expr e) {
isSource(call, index, source, _) and
hasFlow(source, sink) and
isSink(sink, e)
}
/**
@@ -177,7 +150,7 @@ predicate hasFlow(
* success in writing the output argument at index `index`.
*/
int getMinimumGuardConstant(ScanfFunctionCall call, int index) {
isSource(call, index, _, _, _) and
isSource(call, index, _, _) and
result =
index + 1 -
count(ScanfFormatLiteral f, int n |
@@ -191,7 +164,7 @@ int getMinimumGuardConstant(ScanfFunctionCall call, int index) {
* Holds the access to `e` isn't guarded by a check that ensures that `call` returned
* at least `minGuard`.
*/
predicate hasNonGuardedAccess(ScanfFunctionCall call, Access e, int minGuard) {
predicate hasNonGuardedAccess(ScanfFunctionCall call, Expr e, int minGuard) {
exists(int index |
hasFlow(_, call, index, _, e) and
minGuard = getMinimumGuardConstant(call, index)
@@ -211,7 +184,7 @@ BasicBlock blockGuardedBy(int value, string op, ScanfFunctionCall call) {
exists(GuardCondition g, Expr left, Expr right |
right = g.getAChild() and
value = left.getValue().toInt() and
DataFlow::localExprFlow(call, right)
localExprFlow(call, right)
|
g.ensuresEq(left, right, 0, result, true) and op = "=="
or
@@ -221,9 +194,9 @@ BasicBlock blockGuardedBy(int value, string op, ScanfFunctionCall call) {
)
}
from ScanfFunctionCall call, Access access, int minGuard
where hasNonGuardedAccess(call, access, minGuard)
select access,
from ScanfFunctionCall call, Expr e, int minGuard
where hasNonGuardedAccess(call, e, minGuard)
select e,
"This variable is read, but may not have been written. " +
"It should be guarded by a check that the $@ returns at least " + minGuard + ".", call,
call.toString()

View File

@@ -1,7 +1,8 @@
/**
* @name Potential use after free
* @description An allocated memory block is used after it has been freed. Behavior in such cases is undefined and can cause memory corruption.
* @kind problem
* @kind path-problem
* @precision medium
* @id cpp/use-after-free
* @problem.severity warning
* @security-severity 9.3
@@ -11,56 +12,159 @@
*/
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
import semmle.code.cpp.dataflow.new.DataFlow
import semmle.code.cpp.ir.IR
import FlowAfterFree
import UseAfterFree::PathGraph
/** `e` is an expression that frees the memory pointed to by `v`. */
predicate isFreeExpr(Expr e, StackVariable v) {
exists(VariableAccess va | va.getTarget() = v |
exists(FunctionCall fc | fc = e |
fc.getTarget().hasGlobalOrStdName("free") and
va = fc.getArgument(0)
)
or
e.(DeleteExpr).getExpr() = va
or
e.(DeleteArrayExpr).getExpr() = va
/**
* Holds if `call` is a call to a function that obviously
* doesn't dereference its `i`'th argument.
*/
private predicate externalCallNeverDereferences(FormattingFunctionCall call, int arg) {
exists(int formatArg |
pragma[only_bind_out](call.getFormatArgument(formatArg)) =
pragma[only_bind_out](call.getArgument(arg)) and
call.getFormat().(FormatLiteral).getConvSpec(formatArg) != "%s"
)
}
/** `e` is an expression that (may) dereference `v`. */
predicate isDerefExpr(Expr e, StackVariable v) {
v.getAnAccess() = e and dereferenced(e)
or
isDerefByCallExpr(_, _, e, v)
predicate isUse0(DataFlow::Node n, Expr e) {
e = n.asExpr() and
not isFree(_, e, _) and
(
e = any(PointerDereferenceExpr pde).getOperand()
or
e = any(PointerFieldAccess pfa).getQualifier()
or
e = any(ArrayExpr ae).getArrayBase()
or
e = any(Call call).getQualifier()
or
// Assume any function without a body will dereference the pointer
exists(int i, Call call, Function f |
n.asExpr() = call.getArgument(i) and
f = call.getTarget() and
not f.hasEntryPoint() and
// Exclude known functions we know won't dereference the pointer.
// For example, a call such as `printf("%p", myPointer)`.
not externalCallNeverDereferences(call, i)
)
)
}
/**
* `va` is passed by value as (part of) the `i`th argument in
* call `c`. The target function is either a library function
* or a source code function that dereferences the relevant
* parameter.
*/
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
v.getAnAccess() = va and
va = c.getAnArgumentSubExpr(i) and
not c.passesByReference(i, va) and
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
}
module ParameterSinks {
import semmle.code.cpp.ir.ValueNumbering
class UseAfterFreeReachability extends StackVariableReachability {
UseAfterFreeReachability() { this = "UseAfterFree" }
predicate flowsToUse(DataFlow::Node n) {
isUse0(n, _)
or
exists(DataFlow::Node succ |
flowsToUse(succ) and
DataFlow::localFlowStep(n, succ)
)
}
override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
private predicate flowsFromParam(DataFlow::Node n) {
flowsToUse(n) and
(
n.asParameter().getUnspecifiedType() instanceof PointerType
or
exists(DataFlow::Node prev |
flowsFromParam(prev) and
DataFlow::localFlowStep(prev, n)
)
)
}
override predicate isSink(ControlFlowNode node, StackVariable v) { isDerefExpr(node, v) }
private predicate step(DataFlow::Node n1, DataFlow::Node n2) {
flowsFromParam(n1) and
flowsFromParam(n2) and
DataFlow::localFlowStep(n1, n2)
}
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
definitionBarrier(v, node) or
isFreeExpr(node, v)
private predicate paramToUse(DataFlow::Node n1, DataFlow::Node n2) = fastTC(step/2)(n1, n2)
private predicate hasFlow(
DataFlow::Node source, InitializeParameterInstruction init, DataFlow::Node sink
) {
pragma[only_bind_out](source.asParameter()) = pragma[only_bind_out](init.getParameter()) and
paramToUse(source, sink) and
isUse0(sink, _)
}
private InitializeParameterInstruction getAnAlwaysDereferencedParameter0() {
exists(DataFlow::Node source, DataFlow::Node sink, IRBlock b1, int i1, IRBlock b2, int i2 |
hasFlow(pragma[only_bind_into](source), result, pragma[only_bind_into](sink)) and
source.hasIndexInBlock(b1, pragma[only_bind_into](i1)) and
sink.hasIndexInBlock(b2, pragma[only_bind_into](i2)) and
strictlyPostDominates(b2, i2, b1, i1)
)
}
private CallInstruction getAnAlwaysReachedCallInstruction(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
}
pragma[nomagic]
predicate initializeParameterInFunction(Function f, int i, InitializeParameterInstruction init) {
pragma[only_bind_out](init.getEnclosingFunction()) = f and
init.hasIndex(i)
}
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(_)
)
}
}
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
where r.reaches(free, v, e)
select e, "Memory pointed to by '" + v.getName().toString() + "' may have $@.", free,
"been previously freed"
predicate isUse(DataFlow::Node n, Expr e) {
isUse0(n, e)
or
exists(CallInstruction call, int i, InitializeParameterInstruction init |
n.asOperand().getDef().getUnconvertedResultExpression() = e and
init = ParameterSinks::getAnAlwaysDereferencedParameter() and
call.getArgumentOperand(i) = n.asOperand() and
init.hasIndex(i) and
init.getEnclosingFunction() = call.getStaticCallTarget()
)
}
/**
* `dealloc1` is a deallocation expression, `e` is an expression that dereferences a
* pointer, and the `(dealloc1, e)` pair should be excluded by the `FlowFromFree` library.
*/
bindingset[dealloc1, e]
predicate isExcludeFreeUsePair(DeallocationExpr dealloc1, Expr e) {
// From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
// "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
// to release the memory that was allocated for the MDL structure."
dealloc1.(FunctionCall).getTarget().hasGlobalName("MmFreePagesFromMdl") and
isExFreePoolCall(_, e)
}
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)
select sink.getNode(), source, sink, "Memory may have been previously freed by $@.", dealloc,
dealloc.toString()

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.

View File

@@ -2,7 +2,7 @@
* @name Errors When Double Free
* @description Freeing a previously allocated resource twice can lead to various vulnerabilities in the program.
* @kind problem
* @id cpp/double-free
* @id cpp/experimental-double-free
* @problem.severity warning
* @precision medium
* @tags security

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.6.0
version: 0.6.1-dev
groups:
- cpp
- queries

View File

@@ -1 +0,0 @@
<queries language="cpp"/>

View File

@@ -1,7 +1,7 @@
| file://:0:0:0:0 | short __attribute((__may_alias__)) | type_attributes.c:25:30:25:42 | may_alias |
| type_attributes.c:5:36:5:51 | my_packed_struct | type_attributes.c:5:23:5:32 | packed |
| type_attributes.c:10:54:10:54 | union <unnamed> | type_attributes.c:10:30:10:50 | transparent_union |
| type_attributes.c:16:54:16:54 | union <unnamed> | type_attributes.c:16:30:16:50 | transparent_union |
| type_attributes.c:10:54:10:54 | (unnamed class/struct/union) | type_attributes.c:10:30:10:50 | transparent_union |
| type_attributes.c:16:54:16:54 | (unnamed class/struct/union) | type_attributes.c:16:30:16:50 | transparent_union |
| type_attributes.c:21:37:21:45 | unusedInt | type_attributes.c:21:24:21:29 | unused |
| type_attributes.c:23:13:23:18 | depInt | type_attributes.c:23:36:23:45 | deprecated |
| type_attributes_ms.cpp:1:29:1:29 | X | type_attributes_ms.cpp:1:19:1:26 | novtable |

View File

@@ -1,4 +1,4 @@
| (unnamed class/struct/union) |
| float[3] |
| float[3][3] |
| foo[1] |
| struct <unnamed> |

View File

@@ -3,14 +3,14 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnaly
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest
module ModulusAnalysisInstantiated =
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImpl>>;
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImplRelative>>;
class ModulusAnalysisTest extends InlineExpectationsTest {
ModulusAnalysisTest() { this = "ModulusAnalysisTest" }

View File

@@ -0,0 +1,23 @@
import cpp
import semmle.code.cpp.rangeanalysis.new.SimpleRangeAnalysis
import TestUtilities.InlineExpectationsTest
class RangeAnalysisTest extends InlineExpectationsTest {
RangeAnalysisTest() { this = "RangeAnalysisTest" }
override string getARelevantTag() { result = "overflow" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr e |
tag = "overflow" and
element = e.toString() and
location = e.getLocation() and
value =
strictconcat(string s |
s = "+" and exprMightOverflowPositively(e)
or
s = "-" and exprMightOverflowNegatively(e)
)
)
}
}

View File

@@ -8,9 +8,9 @@ int test1(struct List* p) {
int count = 0;
for (; p; p = p->next) {
count = count+1;
range(count); // $ range===count:p+1 range=>=1
range(count); // $ range===count:p+1
}
range(count); // $ range=>=0
range(count);
return count;
}
@@ -40,13 +40,13 @@ int test4() {
int total = 0;
for (i = 0; i < 2; i = i+1) {
range(i); // $ range=<=1 range=>=0
range(total); // $ range=>=0
range(total);
total += i;
range(total); // $ range=<=i+1 range=<=i+1 range=>=0 range=>=i+0
range(total); // $ range=<=i+1 range=<=i+1 MISSING: range=>=0 range=>=i+0
}
range(total); // $ range=>=0
range(total); // $ MISSING: range=>=0
range(i); // $ range===2
range(total + i); // $ range===i+2 range=>=2 range=>=i+0
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
return total + i;
}
@@ -55,13 +55,13 @@ int test5() {
int total = 0;
for (i = 0; i < 2; i++) {
range(i); // $ range=<=1 range=>=0
range(total); // $ range=>=0
range(total); // $ MISSING: range=>=0
total += i;
range(total); // $ range=<=i+1 range=>=0 range=>=i+0
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
}
range(total); // $ range=>=0
range(total); // $ MISSING: range=>=0
range(i); // $ range===2
range(total + i); // $ range===i+2 range=>=2 range=>=i+0
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
return total + i;
}
@@ -70,9 +70,9 @@ int test6() {
int total = 0;
for (i = 0; i+2 < 4; i = i+1) {
range(i); // $ range=<=1 range=>=0
range(total); // $ range=>=0
range(total); // $ MISSING: range=>=0
total += i;
range(total); // $ range=<=i+1 range=>=0 range=>=i+0
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
}
return total + i;
}
@@ -168,19 +168,19 @@ typedef unsigned long long size_type;
size_type test12_helper() {
static size_type n = 0;
return n++;
return n++; // $ overflow=+
}
int test12() {
size_type Start = 0;
while (Start <= test12_helper()-1)
{
range(Start);
range(Start); // $ MISSING:range=>=0
const size_type Length = test12_helper();
Start += Length + 1;
range(Start);
Start += Length + 1; // $ overflow=+
range(Start); // $ MISSING:range=>=1 MISSING:range=>=Start+1 MISSING:range=">=call to test12_helper+1"
}
range(Start);
range(Start); // $ MISSING:range=>=0
return 1;
}
@@ -190,13 +190,13 @@ int test13(char c, int i) {
unsigned char uc = c;
range(uc);
unsigned int x = 0;
unsigned int y = x-1;
range(y); // $ range===-1
int z = i+1;
unsigned int y = x-1; // $ overflow=-
range(y); // $ range===-1 overflow=-
int z = i+1; // $ overflow=+
range(z); // $ range===i+1
range(c + i + uc + x + y + z);
range((double)(c + i + uc + x + y + z));
return (double)(c + i + uc + x + y + z);
range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1
return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=-
}
// Regression test for ODASA-6013.
@@ -213,8 +213,8 @@ int test14(int x) {
range(c0);
unsigned short s0 = x;
range(s0);
range(x0 + x1 + x2 + x3 + c0 + s0);
return x0 + x1 + x2 + x3 + c0 + s0;
range(x0 + x1 + x2 + x3 + c0 + s0); // $ overflow=+ overflow=+-
return x0 + x1 + x2 + x3 + c0 + s0; // $ overflow=+ overflow=+-
}
long long test15(long long x) {
@@ -243,7 +243,7 @@ int test_unary(int a) {
range(b); // $ range=<=11 range=>=0
int c = -a;
range(c); // $ range=<=0 range=>=-11
range(b+c); // $ range=<=11 range=>=-11
range(b+c); // $ range=<=11 range=>=-11 MISSING:range=">=- ...+0"
total += b+c;
range(total); // $ range=<=0+11 range=<=19 range=>=0-11 range=>=-19
}
@@ -273,7 +273,7 @@ int test_unary(int a) {
range(b); // $ range=<=0 range=>=-7
int c = -a;
range(c); // $ range=<=7 range=>=0
range(b+c); // $ range=>=-7 range=<=7
range(b+c); // $ range=>=-7 range=<=7 MISSING:range="<=- ...+0"
total += b+c;
range(total); // $ range="<=- ...+7" range="<=- ...+15" range="<=- ...+33" range=">=- ...-7" range=">=- ...-15" range=">=- ...-33" range=<=0+44 range=<=52 range=>=0-44 range=>=-52
}
@@ -315,9 +315,9 @@ int test_mult01(int a, int b) {
if (3 <= a && a <= 11 && -13 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=3
range(b); // $ range=<=23 range=>=-13
int r = a*b; // -143 .. 253
int r = a*b; // $ overflow=+- -143 .. 253
range(r);
total += r;
total += r; // $ overflow=+
range(total); // $ MISSING: range=">=... * ...+0"
}
if (3 <= a && a <= 11 && -13 <= b && b <= 0) {
@@ -326,7 +326,7 @@ int test_mult01(int a, int b) {
int r = a*b; // -143 .. 0
range(r); // $ range=<=0 range=>=-143
total += r;
range(total); // $ range=<=3+0 range=>=3-143
range(total); // $ range=>=3-143
}
if (3 <= a && a <= 11 && -13 <= b && b <= -7) {
range(a); // $ range=<=11 range=>=3
@@ -334,9 +334,9 @@ int test_mult01(int a, int b) {
int r = a*b; // -143 .. -21
range(r); // $ range=<=-21 range=>=-143
total += r;
range(total); // $ range=<=3-21 range=>=3-143 range=>=3-286
range(total); // $ range=>=3-143 range=>=3-286
}
range(total); // $ range=<=3+0 range=>=3-143 range=>=3-286
range(total); // $ range=>=3-143 range=>=3-286
return total;
}
@@ -363,9 +363,9 @@ int test_mult02(int a, int b) {
if (0 <= a && a <= 11 && -13 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=0
range(b); // $ range=<=23 range=>=-13
int r = a*b; // -143 .. 253
int r = a*b; // $ overflow=+- -143 .. 253
range(r);
total += r;
total += r; // $ overflow=+
range(total); // $ MISSING: range=">=... * ...+0"
}
if (0 <= a && a <= 11 && -13 <= b && b <= 0) {
@@ -374,7 +374,7 @@ int test_mult02(int a, int b) {
int r = a*b; // -143 .. 0
range(r); // $ range=<=0 range=>=-143
total += r;
range(total); // $ range=<=0+0 range=>=0-143
range(total); // $ range=>=0-143
}
if (0 <= a && a <= 11 && -13 <= b && b <= -7) {
range(a); // $ range=<=11 range=>=0
@@ -382,9 +382,9 @@ int test_mult02(int a, int b) {
int r = a*b; // -143 .. 0
range(r); // $ range=<=0 range=>=-143
total += r;
range(total); // $ range=<=0+0 range=>=0-143 range=>=0-286
range(total); // $ range=>=0-143 range=>=0-286
}
range(total); // $ range=<=0+0 range=>=0-143 range=>=0-286
range(total); // $range=>=0-143 range=>=0-286
return total;
}
@@ -395,7 +395,7 @@ int test_mult03(int a, int b) {
if (-17 <= a && a <= 11 && 5 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=-17
range(b); // $ range=<=23 range=>=5
int r = a*b; // -391 .. 253
int r = a*b; // $ overflow=+- -391 .. 253
range(r);
total += r;
range(total);
@@ -403,33 +403,33 @@ int test_mult03(int a, int b) {
if (-17 <= a && a <= 11 && 0 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=-17
range(b); // $ range=<=23 range=>=0
int r = a*b; // -391 .. 253
int r = a*b; // $ overflow=+- -391 .. 253
range(r);
total += r;
total += r; // $ overflow=+-
range(total);
}
if (-17 <= a && a <= 11 && -13 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=-17
range(b); // $ range=<=23 range=>=-13
int r = a*b; // -391 .. 253
int r = a*b; // $ overflow=+- -391 .. 25
range(r);
total += r;
total += r; // $ overflow=+-
range(total);
}
if (-17 <= a && a <= 11 && -13 <= b && b <= 0) {
range(a); // $ range=<=11 range=>=-17
range(b); // $ range=<=0 range=>=-13
int r = a*b; // -143 .. 221
int r = a*b; // $ overflow=+- -143 .. 221
range(r);
total += r;
total += r; // $ overflow=+-
range(total);
}
if (-17 <= a && a <= 11 && -13 <= b && b <= -7) {
range(a); // $ range=<=11 range=>=-17
range(b); // $ range=<=-7 range=>=-13
int r = a*b; // -143 .. 221
int r = a*b; // $ overflow=+- -143 .. 221
range(r);
total += r;
total += r; // $ overflow=+-
range(total);
}
range(total);
@@ -458,9 +458,9 @@ int test_mult04(int a, int b) {
if (-17 <= a && a <= 0 && -13 <= b && b <= 23) {
range(a); // $ range=<=0 range=>=-17
range(b); // $ range=<=23 range=>=-13
int r = a*b; // -391 .. 221
int r = a*b; // $ overflow=+- -391 .. 221
range(r);
total += r;
total += r; // $ overflow=-
range(total); // $ MISSING: range="<=... * ...+0"
}
if (-17 <= a && a <= 0 && -13 <= b && b <= 0) {
@@ -469,7 +469,7 @@ int test_mult04(int a, int b) {
int r = a*b; // 0 .. 221
range(r); // $ range=<=221 range=>=0
total += r;
range(total); // $ range="<=- ...+221" range=">=- ...+0"
range(total); // $ range="<=- ...+221"
}
if (-17 <= a && a <= 0 && -13 <= b && b <= -7) {
range(a); // $ range=<=0 range=>=-17
@@ -477,9 +477,9 @@ int test_mult04(int a, int b) {
int r = a*b; // 0 .. 221
range(r); // $ range=<=221 range=>=0
total += r;
range(total); // $ range=">=- ...+0" range="<=- ...+221" range="<=- ...+442"
range(total); // $ range="<=- ...+221" range="<=- ...+442"
}
range(total); // $ range=">=- ...+0" range="<=- ...+221" range="<=- ...+442"
range(total); // $ range="<=- ...+221" range="<=- ...+442"
return total;
}
@@ -506,9 +506,9 @@ int test_mult05(int a, int b) {
if (-17 <= a && a <= -2 && -13 <= b && b <= 23) {
range(a); // $ range=<=-2 range=>=-17
range(b); // $ range=<=23 range=>=-13
int r = a*b; // -391 .. 221
int r = a*b; // $ overflow=+- -391 .. 221
range(r);
total += r;
total += r; // $ overflow=-
range(total); // $ MISSING: range="<=... * ...+0"
}
if (-17 <= a && a <= -2 && -13 <= b && b <= 0) {
@@ -517,7 +517,7 @@ int test_mult05(int a, int b) {
int r = a*b; // 0 .. 221
range(r); // $ range=<=221 range=>=0
total += r;
range(total); // $ range="<=- ...+221" range=">=- ...+0"
range(total); // $ range="<=- ...+221"
}
if (-17 <= a && a <= -2 && -13 <= b && b <= -7) {
range(a); // $ range=<=-2 range=>=-17
@@ -525,9 +525,9 @@ int test_mult05(int a, int b) {
int r = a*b; // 14 .. 221
range(r); // $ range=<=221 range=>=14
total += r;
range(total); // $ range="<=- ...+221" range="<=- ...+442" range=">=- ...+14"
range(total); // $ range="<=- ...+221" range="<=- ...+442"
}
range(total); // $ range=">=- ...+0" range="<=- ...+221" range="<=- ...+442"
range(total); // $ range="<=- ...+221" range="<=- ...+442"
return total;
}
@@ -541,7 +541,7 @@ int test16(int x) {
while (i < 3) {
range(i); // $ range=<=2 range=>=0
i++;
range(i); // $ range="==... = ...:i+1" range=<=3 range=>=1
range(i); // $ range=<=3 range=>=1 range="==... = ...:i+1" SPURIOUS:range="==... = ...:i+1"
}
range(d);
d = i;
@@ -586,7 +586,7 @@ unsigned int test_ternary01(unsigned int x) {
(range(x), 500);
range(y4); // $ range=<=500
y5 = (x+1) ?:
(range(x), 500); // $ range===-1
(range(x), 500); // $ overflow=- range===-1
range(y5); // $ range=<=500
y6 = ((unsigned char)(x+1)) ?:
(range(x), 5); // $ range=<=299
@@ -598,8 +598,8 @@ unsigned int test_ternary01(unsigned int x) {
(range(x), 500); // $ range=<=299
range(y8); // y8 <= 300
}
range(y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8); // $ MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
return y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8;
range(y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8); // $ overflow=+ MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
return y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8; // $ overflow=+
}
// Test ternary expression lower bounds.
@@ -628,8 +628,8 @@ unsigned int test_ternary02(unsigned int x) {
(range(x), 5); // $ range=>=300
range(y5); // y6 >= 0
}
range(y1 + y2 + y3 + y4 + y5); // $ range=">=call to range+207" MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
return y1 + y2 + y3 + y4 + y5;
range(y1 + y2 + y3 + y4 + y5); // $ overflow=+ MISSING: range=">=call to range+207" range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
return y1 + y2 + y3 + y4 + y5; // $ overflow=+
}
// Test the comma expression.
@@ -691,9 +691,9 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
range(a); // $ range=<=11 range=>=3
range(b); // $ range=<=23 range=>=0
int r = a*b; // 0 .. 253
range(r); // $ range=>=0 range=<=253
range(r);// $ range=>=0 range=<=253
total += r;
range(total); // $ range=>=0 range=<=506 range=">=(unsigned int)...+0" range="<=(unsigned int)...+253"
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range=<=506 range="<=(unsigned int)...+253"
}
if (3 <= a && a <= 11 && 13 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=3
@@ -701,7 +701,7 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
int r = a*b; // 39 .. 253
range(r); // $ range=>=39 range=<=253
total += r;
range(total); // $ range=>=39 range=<=759 range=">=(unsigned int)...+39" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
range(total); // $ range=>=39 range=<=759 range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+39"
}
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
return total;
@@ -722,14 +722,14 @@ int test_unsigned_mult02(unsigned b) {
int r = 11*b; // 0 .. 253
range(r); // $ range=>=0 range=<=253
total += r;
range(total); // $ range=>=0 range=<=506 range=">=(unsigned int)...+0" range="<=(unsigned int)...+253"
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range="<=(unsigned int)...+253" range=<=506
}
if (13 <= b && b <= 23) {
range(b); // $ range=<=23 range=>=13
int r = 11*b; // 143 .. 253
range(r); // $ range=>=143 range=<=253
total += r;
range(total); // $ range=>=143 range=<=759 range=">=(unsigned int)...+143" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
range(total); // $ range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+143" range=>=143 range=<=759
}
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
return total;
@@ -751,7 +751,7 @@ unsigned long mult_overflow() {
range(x); // $ range===274177
y = 67280421310721UL;
range(y);
xy = x * y;
xy = x * y; // $ overflow=+-
range(xy);
return xy; // BUG: upper bound should be >= 18446744073709551617UL
}
@@ -760,14 +760,14 @@ unsigned long mult_lower_bound(unsigned int ui, unsigned long ul) {
if (ui >= 10) {
range(ui); // $ range=>=10
range((unsigned long)ui); // $ range=>=10
unsigned long result = (unsigned long)ui * ui;
range(result); // $ range=>=100 range=>=100
unsigned long result = (unsigned long)ui * ui; // $ overflow=+
range(result); // $ MISSING: range=>=100
return result; // BUG: upper bound should be >= 18446744065119617025
}
if (ul >= 10) {
range(ul); // $ range=>=10
unsigned long result = ul * ul;
range(result); // $ range=>=100
unsigned long result = ul * ul; // $ overflow=+
range(result); // $ MISSING: range=>=100
return result; // BUG: lower bound should be 0 (overflow is possible)
}
return 0;
@@ -800,13 +800,13 @@ int mul_by_constant(int i, int j) {
i = 5 * i;
range(i); // $ range=<=10 range=>=-5
i = i * -3;
i = i * -3; // $ overflow=+-
range(i); // -30 .. 15
i *= 7;
i *= 7; // $ overflow=+-
range(i); // -210 .. 105
i *= -11;
i *= -11; // $ overflow=+-
range(i); // -1155 .. 2310
}
if (i == -1) {
@@ -815,7 +815,7 @@ int mul_by_constant(int i, int j) {
i = i * (int)0xffFFffFF; // fully converted literal is -1
range(i); // $ range===1
}
i = i * -1;
i = i * -1; // $ overflow=+-
range( i); // -2^31 .. 2^31-1
signed char sc = 1;
@@ -873,11 +873,11 @@ void notequal_refinement(short n) {
}
while (n != 0) {
range(n); // $ range=<=n+0
range(n); // $ MISSING:range=<=n+0
n--; // 1 ..
}
range(n); // $ range=<=n+0 // 0 .. 0
range(n); // $ MISSING:range=<=n+0 // 0 .. 0
}
void notequal_variations(short n, float f) {
@@ -888,7 +888,7 @@ void notequal_variations(short n, float f) {
}
if (n >= 5) {
if (2 * n - 10 == 0) { // Same as `n == 10/2` (modulo overflow)
if (2 * n - 10 == 0) { // $ overflow=+
range(n); // $ range=>=5 MISSING: range===5
return;
}
@@ -921,7 +921,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) {
}
if (ss < 0x8001) { // Lower bound removed in `getDefLowerBounds`
range(ss); // $ range=<=32768 MISSING: range=>=-32768
range(ss); // $ overflow=+ range=<=32768 MISSING: range=>=-32768
}
if ((short)us >= 0) {
@@ -936,7 +936,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) {
range(ss); // -32768 .. 32767
}
if (ss + 1 < sizeof(int)) {
if (ss + 1 < sizeof(int)) { // $ overflow=+
range(ss); // -1 .. 2
}
}
@@ -1020,7 +1020,7 @@ void test_overflow() {
void test_negate_unsigned(unsigned u) {
if(10 < u && u < 20) {
range<unsigned>(-u); // underflows
range<unsigned>(-u); // $ overflow=-
}
}

View File

@@ -6,17 +6,17 @@
return x;
}
if (y - 2 == x && y > 300) {
if (y - 2 == x && y > 300) { // $ overflow=-
range(x + y); // $ range=<=802 range=>=600
return x + y;
}
if (x != y + 1) {
if (x != y + 1) { // $ overflow=+
range(x); // $ range=<=400
int sum = x + y;
int sum = x + y; // $ overflow=+-
} else {
if (y > 300) {
range(x); // $ range=>=302 range=<=400 range===y+1
range(x); // $ range=>=302 range=<=400 range=<=y+1 MISSING: range===y+1
range(y); // $ range=>=301 range=<=399 range===x-1
int sum = x + y;
}
@@ -38,10 +38,10 @@
return x;
}
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) {
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) { // $ overflow=+ overflow=-
range(x); // $ range===349 range===y+1 range===z-1
range(y); // $ range===348 range===x-1 range===z-2
range(z); // $ range===350 range===x+1 range===y+2
range(y); // $ range===348 range=>=x-1 range===z-2 MISSING: range===x-1
range(z); // $ range===350 range=<=y+2 MISSING: range===x+1 range===y+2
return x + y + z;
}
}

View File

@@ -3,12 +3,13 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest
module SignAnalysisInstantiated = SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImpl>>;
module SignAnalysisInstantiated =
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
class SignAnalysisTest extends InlineExpectationsTest {
SignAnalysisTest() { this = "SignAnalysisTest" }

View File

@@ -1,6 +1,6 @@
| a1.c:6:16:6:16 | struct <unnamed> | 0 members | 2 locations | -1 | <none> |
| a1.c:10:16:10:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
| a1.c:17:16:17:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
| a1.c:6:16:6:16 | (unnamed class/struct/union) | 0 members | 2 locations | -1 | <none> |
| a1.c:10:16:10:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
| a1.c:17:16:17:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 0 | empty |
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 1 | nonempty |
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 2 | i |
@@ -9,9 +9,9 @@
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 0 | empty |
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 1 | nonempty |
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 2 | i |
| a2.c:6:16:6:16 | struct <unnamed> | 0 members | 2 locations | -1 | <none> |
| a2.c:10:16:10:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
| a2.c:17:16:17:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
| a2.c:6:16:6:16 | (unnamed class/struct/union) | 0 members | 2 locations | -1 | <none> |
| a2.c:10:16:10:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
| a2.c:17:16:17:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 0 | empty |
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 1 | nonempty |
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 2 | i |

View File

@@ -1,5 +1,5 @@
| a1.c:10:16:10:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
| a1.c:17:16:17:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
| a1.c:10:16:10:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
| a1.c:17:16:17:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
| a1.c:24:8:24:10 | Foo | 0 | file://:0:0:0:0 | anon_empty_t * | 1 types |
| a1.c:24:8:24:10 | Foo | 1 | file://:0:0:0:0 | anon_nonempty_t * | 1 types |
| a1.c:24:8:24:10 | Foo | 2 | file://:0:0:0:0 | int | 1 types |
@@ -7,8 +7,8 @@
| a1.c:36:8:36:10 | Bar | 0 | file://:0:0:0:0 | Empty * | 1 types |
| a1.c:36:8:36:10 | Bar | 1 | file://:0:0:0:0 | NonEmpty * | 1 types |
| a1.c:36:8:36:10 | Bar | 2 | file://:0:0:0:0 | int | 1 types |
| a2.c:10:16:10:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
| a2.c:17:16:17:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
| a2.c:10:16:10:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
| a2.c:17:16:17:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
| a2.c:24:8:24:10 | Foo | 0 | file://:0:0:0:0 | anon_empty_t * | 1 types |
| a2.c:24:8:24:10 | Foo | 1 | file://:0:0:0:0 | anon_nonempty_t * | 1 types |
| a2.c:24:8:24:10 | Foo | 2 | file://:0:0:0:0 | int | 1 types |

View File

@@ -1 +0,0 @@
<queries language="cpp"/>

View File

@@ -0,0 +1,96 @@
edges
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
| test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a |
| test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a |
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
| test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a |
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
| test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a |
| test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... |
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
nodes
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
| test_free.cpp:30:10:30:10 | a | semmle.label | a |
| test_free.cpp:31:27:31:27 | a | semmle.label | a |
| test_free.cpp:35:10:35:10 | a | semmle.label | a |
| test_free.cpp:37:27:37:27 | a | semmle.label | a |
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
| test_free.cpp:50:27:50:27 | a | semmle.label | a |
| test_free.cpp:51:10:51:10 | a | semmle.label | a |
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
| test_free.cpp:72:14:72:14 | a | semmle.label | a |
| test_free.cpp:72:14:72:14 | a | semmle.label | a |
| test_free.cpp:101:10:101:10 | a | semmle.label | a |
| test_free.cpp:103:10:103:10 | a | semmle.label | a |
| test_free.cpp:128:10:128:11 | * ... | semmle.label | * ... |
| test_free.cpp:129:10:129:11 | * ... | semmle.label | * ... |
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
| test_free.cpp:207:10:207:10 | a | semmle.label | a |
| test_free.cpp:207:10:207:10 | a | semmle.label | a |
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
subpaths
#select
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:31:27:31:27 | a | test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:30:5:30:8 | call to free | call to free |
| test_free.cpp:37:27:37:27 | a | test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:35:5:35:8 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:51:10:51:10 | a | test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:50:22:50:25 | call to free | call to free |
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:103:10:103:10 | a | test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
| test_free.cpp:129:10:129:11 | * ... | test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... | Memory pointed to by '* ...' may already have been freed by $@. | test_free.cpp:128:5:128:8 | call to free | call to free |
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |

View File

@@ -0,0 +1 @@
Critical/DoubleFree.ql

View File

@@ -26,6 +26,72 @@
| test.cpp:128:15:128:16 | v4 |
| test.cpp:185:10:185:12 | cpy |
| test.cpp:199:10:199:12 | cpy |
| test_free.cpp:11:10:11:10 | a |
| test_free.cpp:14:10:14:10 | a |
| test_free.cpp:16:10:16:10 | a |
| test_free.cpp:18:18:18:18 | a |
| test_free.cpp:23:10:23:10 | a |
| test_free.cpp:25:10:25:10 | a |
| test_free.cpp:26:10:26:10 | b |
| test_free.cpp:30:10:30:10 | a |
| test_free.cpp:31:27:31:27 | a |
| test_free.cpp:35:10:35:10 | a |
| test_free.cpp:37:27:37:27 | a |
| test_free.cpp:42:27:42:27 | a |
| test_free.cpp:44:27:44:27 | a |
| test_free.cpp:46:10:46:10 | a |
| test_free.cpp:50:27:50:27 | a |
| test_free.cpp:51:10:51:10 | a |
| test_free.cpp:55:27:55:27 | a |
| test_free.cpp:57:10:57:10 | a |
| test_free.cpp:61:10:61:10 | a |
| test_free.cpp:63:10:63:10 | b |
| test_free.cpp:69:10:69:10 | a |
| test_free.cpp:72:14:72:14 | a |
| test_free.cpp:83:12:83:12 | a |
| test_free.cpp:85:12:85:12 | a |
| test_free.cpp:90:10:90:10 | a |
| test_free.cpp:95:10:95:10 | a |
| test_free.cpp:101:10:101:10 | a |
| test_free.cpp:102:23:102:23 | a |
| test_free.cpp:103:10:103:10 | a |
| test_free.cpp:104:10:104:10 | b |
| test_free.cpp:107:23:107:23 | a |
| test_free.cpp:112:14:112:14 | a |
| test_free.cpp:114:10:114:10 | b |
| test_free.cpp:118:23:118:23 | a |
| test_free.cpp:119:17:119:17 | b |
| test_free.cpp:121:14:121:14 | a |
| test_free.cpp:126:10:126:11 | * ... |
| test_free.cpp:128:10:128:11 | * ... |
| test_free.cpp:129:10:129:11 | * ... |
| test_free.cpp:131:10:131:13 | access to array |
| test_free.cpp:132:10:132:13 | access to array |
| test_free.cpp:143:27:143:30 | data |
| test_free.cpp:145:14:145:22 | * ... |
| test_free.cpp:148:10:148:17 | list_ptr |
| test_free.cpp:152:27:152:27 | a |
| test_free.cpp:154:10:154:10 | a |
| test_free.cpp:159:14:159:15 | * ... |
| test_free.cpp:162:10:162:10 | a |
| test_free.cpp:167:23:167:23 | a |
| test_free.cpp:173:10:173:10 | a |
| test_free.cpp:181:10:181:10 | a |
| test_free.cpp:183:10:183:10 | a |
| test_free.cpp:185:10:185:10 | a |
| test_free.cpp:188:10:188:10 | a |
| test_free.cpp:193:20:193:20 | a |
| test_free.cpp:199:20:199:20 | a |
| test_free.cpp:205:10:205:10 | a |
| test_free.cpp:207:10:207:10 | a |
| test_free.cpp:209:10:209:10 | a |
| test_free.cpp:213:10:213:10 | a |
| test_free.cpp:216:10:216:10 | a |
| test_free.cpp:220:10:220:10 | a |
| test_free.cpp:227:24:227:45 | memory_descriptor_list |
| test_free.cpp:233:14:233:15 | * ... |
| test_free.cpp:239:14:239:15 | * ... |
| test_free.cpp:245:10:245:11 | * ... |
| virtual.cpp:18:10:18:10 | a |
| virtual.cpp:19:10:19:10 | c |
| virtual.cpp:38:10:38:10 | b |

View File

@@ -0,0 +1 @@
| test_free.cpp:36:22:36:35 | ... = ... | This memory allocation may not be released at $@. | test_free.cpp:38:1:38:1 | return ... | this exit point |

View File

@@ -11,3 +11,4 @@
| test.cpp:156:3:156:26 | new | This memory is never freed. |
| test.cpp:157:3:157:26 | new[] | This memory is never freed. |
| test.cpp:169:14:169:19 | call to strdup | This memory is never freed. |
| test_free.cpp:167:15:167:21 | call to realloc | This memory is never freed. |

View File

@@ -0,0 +1,100 @@
edges
| test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a |
| test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a |
| test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a |
| test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a |
| test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a |
| test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a |
| test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a |
| test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a |
| test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a |
| test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a |
| test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a |
| test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a |
| test_free.cpp:95:10:95:10 | a | test_free.cpp:96:9:96:9 | a |
| test_free.cpp:101:10:101:10 | a | test_free.cpp:102:23:102:23 | a |
| test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a |
| test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a |
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
nodes
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
| test_free.cpp:12:5:12:5 | a | semmle.label | a |
| test_free.cpp:13:6:13:6 | a | semmle.label | a |
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
| test_free.cpp:45:5:45:5 | a | semmle.label | a |
| test_free.cpp:45:5:45:5 | a | semmle.label | a |
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
| test_free.cpp:71:9:71:9 | a | semmle.label | a |
| test_free.cpp:90:10:90:10 | a | semmle.label | a |
| test_free.cpp:90:10:90:10 | a | semmle.label | a |
| test_free.cpp:91:5:91:5 | a | semmle.label | a |
| test_free.cpp:95:10:95:10 | a | semmle.label | a |
| test_free.cpp:96:9:96:9 | a | semmle.label | a |
| test_free.cpp:101:10:101:10 | a | semmle.label | a |
| test_free.cpp:102:23:102:23 | a | semmle.label | a |
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
| test_free.cpp:153:5:153:5 | a | semmle.label | a |
| test_free.cpp:233:14:233:15 | * ... | semmle.label | * ... |
| test_free.cpp:233:14:233:15 | * ... | semmle.label | * ... |
| test_free.cpp:236:9:236:10 | * ... | semmle.label | * ... |
| test_free.cpp:236:9:236:10 | * ... | semmle.label | * ... |
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
| test_free.cpp:241:10:241:10 | b | semmle.label | b |
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
subpaths
#select
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:13:6:13:6 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:13:6:13:6 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
| test_free.cpp:45:5:45:5 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:45:5:45:5 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
| test_free.cpp:71:9:71:9 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a | Memory may have been previously freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:71:9:71:9 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a | Memory may have been previously freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
| test_free.cpp:91:5:91:5 | a | test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a | Memory may have been previously freed by $@. | test_free.cpp:90:5:90:8 | call to free | call to free |
| test_free.cpp:91:5:91:5 | a | test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a | Memory may have been previously freed by $@. | test_free.cpp:90:5:90:8 | call to free | call to free |
| test_free.cpp:96:9:96:9 | a | test_free.cpp:95:10:95:10 | a | test_free.cpp:96:9:96:9 | a | Memory may have been previously freed by $@. | test_free.cpp:95:5:95:8 | call to free | call to free |
| test_free.cpp:102:23:102:23 | a | test_free.cpp:101:10:101:10 | a | test_free.cpp:102:23:102:23 | a | Memory may have been previously freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
| test_free.cpp:153:5:153:5 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a | Memory may have been previously freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:153:5:153:5 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a | Memory may have been previously freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |

View File

@@ -0,0 +1 @@
Critical/UseAfterFree.ql

View File

@@ -0,0 +1,247 @@
void *malloc(int);
void free(void *);
bool condition();
void use(void*);
void *realloc(void*, unsigned long);
int strlen(char*);
int asprintf(char ** strp, const char * fmt, ...);
void* test_double_free1(int *a) {
free(a); // GOOD
a[5] = 5; // BAD
*a = 5; // BAD
free(a); // BAD
a = (int*) malloc(8);
free(a); // GOOD
a = (int*) malloc(8);
if (!a) free(a);
return a;
}
void test_double_free_aliasing(void *a, void* b) {
free(a); // GOOD
a = b;
free(a); // GOOD
free(b); // BAD [NOT DETECTED]
}
void test_dominance1(void *a) {
free(a);
if (condition()) free(a); // BAD
}
void test_dominance2(void *a) {
free(a);
if (condition()) a = malloc(10);
if (condition()) free(a); // BAD
}
void test_post_dominance1(int *a)
{
if (condition()) free(a);
if (condition()) a[2] = 5; // BAD [NOT DETECTED]
if (condition()) free(a); // BAD [NOT DETECTED]
a[2] = 5; // BAD
free(a); // BAD
}
void test_post_dominance2(void *a) {
if (condition()) free(a);
free(a); // BAD
}
void test_post_dominance3(void *a) {
if (condition()) free(a);
a = malloc(10);
free(a); // GOOD
}
void test_use_after_free6(int *a, int *b) {
free(a);
a=b;
free(b);
if (condition()) a[0] = 5; // BAD [NOT DETECTED]
}
void test_use_after_free7(int *a) {
a[0] = 42;
free(a);
if (a[3]) { // BAD
free(a); // BAD
}
}
class A {
public:
void f();
};
void test_new1() {
A *a = new A();
delete(a);
a->f(); // BAD [NOT DETECTED]
delete(a); // BAD [NOT DETECTED]
}
void test_dereference1(A *a) {
a->f(); // GOOD
free(a);
a->f(); // BAD
}
void* use_after_free(void *a) {
free(a);
use(a); // BAD
return a; // BAD
}
void test_realloc1(void *a) {
free(a);
void *b = realloc(a, sizeof(a)*3); // BAD [NOT DETECTED by cpp/double-free]
free(a); // BAD
free(b); // GOOD
}
void* test_realloc2(char *a) {
void *b = realloc(a, strlen(a)+3); // GOOD
// From the man page on return values from realloc and reallocarray:
// "If these functions fail, the original block is left untouched; it is not freed or moved."
if (!b) {
free(a); // GOOD
}
free(b); // GOOD
}
void test_realloc3(void *a) {
void *b = realloc(a, 100);
if (b) free(b); // GOOD
if (!b) {
free(a); // GOOD
}
}
void test_ptr_deref(void ** a) {
free(*a);
*a = malloc(10);
free(*a); // GOOD
free(*a); // BAD [NOT DETECTED]
*a = malloc(10);
free(a[0]); // GOOD
free(a[1]); // GOOD
}
struct list {
struct list *next;
void* data;
};
void test_loop1(struct list ** list_ptr) {
struct list *next;
while (*list_ptr) { // GOOD
free((*list_ptr)->data); // GOOD
next = (*list_ptr)->next; // GOOD
free(*list_ptr); // GOOD
*list_ptr = next; // GOOD
}
free(list_ptr); // GOOD
}
void test_use_after_free8(struct list * a) {
if (condition()) free(a);
a->data = malloc(10); // BAD
free(a); // BAD
}
void test_loop2(char ** a) {
while (*a) { // GOOD
free(*a); // GOOD
a++;
}
free(a); // GOOD
}
void* test_realloc4() {
void *a = 0;
void *b = realloc(a, 10); // BAD for cpp/memory-never-freed
if (!b) { return a; }
return b;
}
void test_sizeof(int *a) {
free(a);
int x = sizeof(a[0]); // GOOD
}
void call_by_reference(char * &a);
int custom_alloc_func(char ** a);
void test_reassign(char *a) {
free(a); // GOOD
asprintf(&a, "Hello world"); // GOOD
free(a); //GOOD
call_by_reference(a); // GOOD
free(a); // GOOD
int v;
if (v = custom_alloc_func(&a)) return;
free(a); // GOOD
}
char* test_return1(char *a) {
int ret = condition();
if (!ret) free(a);
return (ret ? a : 0);
}
char* test_return2(char *a) {
int ret = condition();
if (!ret) free(a);
if (ret) return a;
else return 0;
}
void test_condition1(char *a) {
free(a);
if (asprintf(&a, "Hello world") || condition());
free(a); //GOOD
if (condition() || asprintf(&a, "Hello world"));
free(a); // BAD
}
void test_condition2(char *a) {
free(a);
if (condition()) a = (char*) malloc(10);
else custom_alloc_func(&a);
free(a); // GOOD
}
void* test_return1(void *a) {
free(a);
return a;
}
void MmFreePagesFromMdl(void*);
void ExFreePool(void*);
void test_ms_free(void * memory_descriptor_list) {
MmFreePagesFromMdl(memory_descriptor_list); //GOOD
ExFreePool(memory_descriptor_list); // GOOD
}
void test_loop3(char ** a, char ** b) {
if (*a) {
free(*a);
a++;
}
use(*a); // GOOD [FALSE POSITIVE]
for (;*b; b++) {
free(*b);
}
use(*b); // GOOD [FALSE POSITIVE]
}
void test_deref(char **a) {
free(*a);
use(*a); // GOOD [FALSE POSITIVE]
}

View File

@@ -1,9 +1,8 @@
| test.cpp:35:7:35:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:34:3:34:7 | call to scanf | call to scanf |
| test.cpp:51:7:51:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:50:3:50:7 | call to scanf | call to scanf |
| test.cpp:68:7:68:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:67:3:67:7 | call to scanf | call to scanf |
| test.cpp:80:7:80:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:79:3:79:7 | call to scanf | call to scanf |
| test.cpp:90:8:90:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:89:3:89:7 | call to scanf | call to scanf |
| test.cpp:98:8:98:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:97:3:97:7 | call to scanf | call to scanf |
| test.cpp:90:7:90:8 | * ... | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:89:3:89:7 | call to scanf | call to scanf |
| test.cpp:98:7:98:8 | * ... | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:97:3:97:7 | call to scanf | call to scanf |
| test.cpp:108:7:108:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:107:3:107:8 | call to fscanf | call to fscanf |
| test.cpp:115:7:115:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:114:3:114:8 | call to sscanf | call to sscanf |
| test.cpp:164:8:164:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:162:7:162:11 | call to scanf | call to scanf |
@@ -12,13 +11,9 @@
| test.cpp:224:8:224:8 | j | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:221:7:221:11 | call to scanf | call to scanf |
| test.cpp:248:9:248:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:246:25:246:29 | call to scanf | call to scanf |
| test.cpp:252:9:252:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:250:14:250:18 | call to scanf | call to scanf |
| test.cpp:264:7:264:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:263:3:263:7 | call to scanf | call to scanf |
| test.cpp:272:7:272:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:271:3:271:7 | call to scanf | call to scanf |
| test.cpp:280:7:280:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:279:3:279:7 | call to scanf | call to scanf |
| test.cpp:292:7:292:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:291:3:291:7 | call to scanf | call to scanf |
| test.cpp:302:8:302:12 | ptr_i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:301:3:301:7 | call to scanf | call to scanf |
| test.cpp:310:7:310:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:309:3:309:7 | call to scanf | call to scanf |
| test.cpp:404:25:404:25 | u | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:403:6:403:11 | call to sscanf | call to sscanf |
| test.cpp:416:7:416:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:413:7:413:11 | call to scanf | call to scanf |
| test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
| test.cpp:430:6:430:6 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:429:2:429:6 | call to scanf | call to scanf |

View File

@@ -48,7 +48,7 @@ int main()
int i = 0;
scanf("%d", &i);
use(i); // BAD. Design choice: already initialized variables shouldn't make a difference.
use(i); // GOOD. Design choice: already initialized variables are fine.
}
{
@@ -261,7 +261,7 @@ int main()
i = 0;
scanf("%d", &i);
use(i); // BAD
use(i); // GOOD
}
{
@@ -269,7 +269,7 @@ int main()
set_by_ref(i);
scanf("%d", &i);
use(i); // BAD
use(i); // GOOD [FALSE POSITIVE]
}
{
@@ -277,7 +277,7 @@ int main()
set_by_ptr(&i);
scanf("%d", &i);
use(i); // BAD
use(i); // GOOD [FALSE POSITIVE]
}
{
@@ -299,7 +299,7 @@ int main()
int *ptr_i = &i;
scanf("%d", &i);
use(*ptr_i); // BAD: may not have written `i`
use(*ptr_i); // BAD [NOT DETECTED]: may not have written `i`
}
{
@@ -307,7 +307,7 @@ int main()
int *ptr_i = &i;
scanf("%d", ptr_i);
use(i); // BAD: may not have written `*ptr_i`
use(i); // BAD [NOT DETECTED]: may not have written `*ptr_i`
}
{
@@ -427,5 +427,5 @@ void scan_and_write() {
void scan_and_static_variable() {
static int i;
scanf("%d", &i);
use(i); // GOOD [FALSE POSITIVE]: static variables are always 0-initialized
use(i); // GOOD: static variables are always 0-initialized
}

View File

@@ -1,9 +1,74 @@
| test.cpp:36:6:36:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:35:2:35:5 | call to free | been previously freed |
| test.cpp:70:7:70:10 | data | Memory pointed to by 'data' may have $@. | test.cpp:67:2:67:5 | call to free | been previously freed |
| test.cpp:107:6:107:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:105:2:105:5 | call to free | been previously freed |
| test.cpp:117:6:117:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:115:2:115:5 | call to free | been previously freed |
| test.cpp:150:2:150:2 | c | Memory pointed to by 'c' may have $@. | test.cpp:149:2:149:10 | delete | been previously freed |
| test.cpp:151:4:151:4 | c | Memory pointed to by 'c' may have $@. | test.cpp:149:2:149:10 | delete | been previously freed |
| test.cpp:170:6:170:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:165:2:165:5 | call to free | been previously freed |
| test.cpp:193:6:193:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:191:3:191:6 | call to free | been previously freed |
| test.cpp:201:6:201:6 | x | Memory pointed to by 'x' may have $@. | test.cpp:200:2:200:9 | delete | been previously freed |
edges
| test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data |
| test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data |
| test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data |
| test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data |
| test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data |
| test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data |
| test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data |
| test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data |
| test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data |
| test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data |
| test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data |
| test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data |
| test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data |
| test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data |
| test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data |
| test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data |
| test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data |
| test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data |
| test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data |
| test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data |
nodes
| test.cpp:39:7:39:10 | data | semmle.label | data |
| test.cpp:39:7:39:10 | data | semmle.label | data |
| test.cpp:41:6:41:9 | data | semmle.label | data |
| test.cpp:75:7:75:10 | data | semmle.label | data |
| test.cpp:75:7:75:10 | data | semmle.label | data |
| test.cpp:79:7:79:10 | data | semmle.label | data |
| test.cpp:106:7:106:10 | data | semmle.label | data |
| test.cpp:106:7:106:10 | data | semmle.label | data |
| test.cpp:108:6:108:9 | data | semmle.label | data |
| test.cpp:116:7:116:10 | data | semmle.label | data |
| test.cpp:116:7:116:10 | data | semmle.label | data |
| test.cpp:119:6:119:9 | data | semmle.label | data |
| test.cpp:127:7:127:10 | data | semmle.label | data |
| test.cpp:127:7:127:10 | data | semmle.label | data |
| test.cpp:130:6:130:9 | data | semmle.label | data |
| test.cpp:138:7:138:10 | data | semmle.label | data |
| test.cpp:138:7:138:10 | data | semmle.label | data |
| test.cpp:141:6:141:9 | data | semmle.label | data |
| test.cpp:181:7:181:10 | data | semmle.label | data |
| test.cpp:181:7:181:10 | data | semmle.label | data |
| test.cpp:186:6:186:9 | data | semmle.label | data |
| test.cpp:192:7:192:10 | data | semmle.label | data |
| test.cpp:192:7:192:10 | data | semmle.label | data |
| test.cpp:197:6:197:9 | data | semmle.label | data |
| test.cpp:203:7:203:10 | data | semmle.label | data |
| test.cpp:203:7:203:10 | data | semmle.label | data |
| test.cpp:207:8:207:11 | data | semmle.label | data |
| test.cpp:207:8:207:11 | data | semmle.label | data |
| test.cpp:209:6:209:9 | data | semmle.label | data |
| test.cpp:209:6:209:9 | data | semmle.label | data |
subpaths
#select
| test.cpp:41:6:41:9 | data | test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data | Memory may have been previously freed by $@. | test.cpp:39:2:39:5 | call to free | call to free |
| test.cpp:41:6:41:9 | data | test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data | Memory may have been previously freed by $@. | test.cpp:39:2:39:5 | call to free | call to free |
| test.cpp:79:7:79:10 | data | test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data | Memory may have been previously freed by $@. | test.cpp:75:2:75:5 | call to free | call to free |
| test.cpp:79:7:79:10 | data | test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data | Memory may have been previously freed by $@. | test.cpp:75:2:75:5 | call to free | call to free |
| test.cpp:108:6:108:9 | data | test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data | Memory may have been previously freed by $@. | test.cpp:106:2:106:5 | call to free | call to free |
| test.cpp:108:6:108:9 | data | test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data | Memory may have been previously freed by $@. | test.cpp:106:2:106:5 | call to free | call to free |
| test.cpp:119:6:119:9 | data | test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data | Memory may have been previously freed by $@. | test.cpp:116:2:116:5 | call to free | call to free |
| test.cpp:119:6:119:9 | data | test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data | Memory may have been previously freed by $@. | test.cpp:116:2:116:5 | call to free | call to free |
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
| test.cpp:141:6:141:9 | data | test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data | Memory may have been previously freed by $@. | test.cpp:138:2:138:5 | call to free | call to free |
| test.cpp:141:6:141:9 | data | test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data | Memory may have been previously freed by $@. | test.cpp:138:2:138:5 | call to free | call to free |
| test.cpp:186:6:186:9 | data | test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data | Memory may have been previously freed by $@. | test.cpp:181:2:181:5 | call to free | call to free |
| test.cpp:186:6:186:9 | data | test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data | Memory may have been previously freed by $@. | test.cpp:181:2:181:5 | call to free | call to free |
| test.cpp:197:6:197:9 | data | test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data | Memory may have been previously freed by $@. | test.cpp:192:2:192:5 | call to free | call to free |
| test.cpp:197:6:197:9 | data | test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data | Memory may have been previously freed by $@. | test.cpp:192:2:192:5 | call to free | call to free |
| test.cpp:209:6:209:9 | data | test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:203:2:203:5 | call to free | call to free |
| test.cpp:209:6:209:9 | data | test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:203:2:203:5 | call to free | call to free |
| test.cpp:209:6:209:9 | data | test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:207:3:207:6 | call to free | call to free |
| test.cpp:209:6:209:9 | data | test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:207:3:207:6 | call to free | call to free |

View File

@@ -6,14 +6,18 @@ typedef unsigned long size_t;
void *malloc(size_t size);
void free(void *ptr);
void useExternal(char* data);
void useExternal(...);
void use(char* data)
void use_if_nonzero(char* data)
{
if (data)
useExternal(data);
}
void use(char* data) {
useExternal(*data);
}
[[noreturn]]
void noReturn();
@@ -31,8 +35,9 @@ void test1()
{
char* data;
data = (char *)malloc(100*sizeof(char));
use(data); // GOOD
use_if_nonzero(data); // GOOD
free(data);
use_if_nonzero(data); // BAD [NOT DETECTED]
use(data); // BAD
}
@@ -42,9 +47,11 @@ void test2()
data = (char *)malloc(100*sizeof(char));
free(data);
myMalloc(&data);
use_if_nonzero(data); // GOOD
use(data); // GOOD
free(data);
myMalloc2(data);
use_if_nonzero(data); // GOOD
use(data); // GOOD
}
@@ -56,6 +63,7 @@ void test3()
data = NULL;
if (data)
{
use_if_nonzero(data); // GOOD
use(data); // GOOD
}
}
@@ -67,6 +75,7 @@ void test4()
free(data);
if (data)
{
use_if_nonzero(data); // BAD [NOT DETECTED]
use(data); // BAD
}
}
@@ -85,7 +94,8 @@ char* returnsFreedData(int i)
void test5()
{
char* data = returnsFreedData(1);
use(data); // BAD (NOT REPORTED)
use_if_nonzero(data); // BAD [NOT DETECTED]
use(data); // BAD [NOT DETECTED]
}
void test6()
@@ -94,7 +104,8 @@ void test6()
data = (char *)malloc(100*sizeof(char));
data2 = data;
free(data);
use(data2); // BAD (NOT REPORTED)
use_if_nonzero(data2); // BAD [NOT DETECTED]
use(data); // BAD
}
void test7()
@@ -104,6 +115,7 @@ void test7()
data2 = data;
free(data);
data2 = NULL;
use_if_nonzero(data); // BAD [NOT DETECTED]
use(data); // BAD
}
@@ -114,6 +126,7 @@ void test8()
data = data2;
free(data);
data2 = NULL;
use_if_nonzero(data); // BAD [NOT DETECTED]
use(data); // BAD
}
@@ -124,13 +137,15 @@ void test9()
char *data, *data2;
free(data);
noReturnWrapper();
use(data); // GOOD
use_if_nonzero(data); // GOOD
use(data); // GOOD [FALSE POSITIVE]
}
void test10()
{
for (char *data; true; data = NULL)
{
use_if_nonzero(data); // GOOD
use(data); // GOOD
free(data);
}
@@ -156,7 +171,8 @@ template<class T> T test()
T* x;
use(x); // GOOD
delete x;
use(x); // BAD
use_if_nonzero(x); // BAD [NOT DETECTED]
use(x); // BAD [NOT DETECTED]
}
void test12(int count)
@@ -178,7 +194,7 @@ void test13()
{
data = NULL;
}
use(data); // GOOD
use(data); // GOOD [FALSE POSITIVE]
}
void test14()
@@ -198,7 +214,7 @@ template<class T> T test15()
T* x;
use(x); // GOOD
delete x;
use(x); // BAD
use(x); // BAD [NOT DETECTED]
}
void test15runner(void)
{

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.5.0
version: 1.5.1-dev
groups:
- csharp
- solorigate

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.5.0
version: 1.5.1-dev
groups:
- csharp
- solorigate

View File

@@ -1 +0,0 @@
<queries language="csharp"/>

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all
version: 0.6.0
version: 0.6.1-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp

View File

@@ -52,23 +52,24 @@ class IDbCommandConstructionSqlExpr extends SqlExpr, ObjectCreation {
class DapperCommandDefinitionMethodCallSqlExpr extends SqlExpr, ObjectCreation {
DapperCommandDefinitionMethodCallSqlExpr() {
this.getObjectType() instanceof Dapper::CommandDefinitionStruct and
exists(Conf c | c.hasFlow(DataFlow::exprNode(this), _))
DapperCommandDefinitionMethodCallSql::flow(DataFlow::exprNode(this), _)
}
override Expr getSql() { result = this.getArgumentForName("commandText") }
}
private class Conf extends DataFlow4::Configuration {
Conf() { this = "DapperCommandDefinitionFlowConfig" }
override predicate isSource(DataFlow::Node node) {
private module DapperCommandDefitionMethodCallSqlConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
node.asExpr().(ObjectCreation).getObjectType() instanceof Dapper::CommandDefinitionStruct
}
override predicate isSink(DataFlow::Node node) {
predicate isSink(DataFlow::Node node) {
exists(MethodCall mc |
mc.getTarget() = any(Dapper::SqlMapperClass c).getAQueryMethod() and
node.asExpr() = mc.getArgumentForName("command")
)
}
}
private module DapperCommandDefinitionMethodCallSql =
DataFlow::Global<DapperCommandDefitionMethodCallSqlConfig>;

View File

@@ -162,18 +162,14 @@ class XmlReaderSettingsCreation extends ObjectCreation {
}
}
private class SettingsDataFlowConfig extends DataFlow3::Configuration {
SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" }
private module SettingsDataFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof XmlReaderSettingsCreation }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof XmlReaderSettingsCreation
}
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() instanceof XmlReaderSettingsInstance
}
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof XmlReaderSettingsInstance }
}
private module SettingsDataFlow = DataFlow::Global<SettingsDataFlowConfig>;
/** A call to `XmlReader.Create`. */
class XmlReaderCreateCall extends MethodCall {
XmlReaderCreateCall() { this.getTarget() = any(SystemXmlXmlReaderClass r).getCreateMethod() }
@@ -190,8 +186,6 @@ class XmlReaderSettingsInstance extends Expr {
/** Gets a possible creation point for this instance of `XmlReaderSettings`. */
XmlReaderSettingsCreation getASettingsCreation() {
exists(SettingsDataFlowConfig settingsFlow |
settingsFlow.hasFlow(DataFlow::exprNode(result), DataFlow::exprNode(this))
)
SettingsDataFlow::flow(DataFlow::exprNode(result), DataFlow::exprNode(this))
}
}

View File

@@ -78,10 +78,12 @@ predicate isExponentialRegex(StringLiteral s) {
}
/**
* DEPRECATED: Use `ExponentialRegexDataflow` instead.
*
* A data flow configuration for tracking exponential worst case time regular expression string
* literals to the pattern argument of a regex.
*/
class ExponentialRegexDataflow extends DataFlow2::Configuration {
deprecated class ExponentialRegexDataflow extends DataFlow2::Configuration {
ExponentialRegexDataflow() { this = "ExponentialRegex" }
override predicate isSource(DataFlow::Node s) { isExponentialRegex(s.asExpr()) }
@@ -89,15 +91,27 @@ class ExponentialRegexDataflow extends DataFlow2::Configuration {
override predicate isSink(DataFlow::Node s) { s.asExpr() = any(RegexOperation c).getPattern() }
}
/**
* A data flow configuration for tracking exponential worst case time regular expression string
* literals to the pattern argument of a regex.
*/
private module ExponentialRegexDataFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node s) { isExponentialRegex(s.asExpr()) }
predicate isSink(DataFlow::Node s) { s.asExpr() = any(RegexOperation c).getPattern() }
}
module ExponentialRegexDataFlow = DataFlow::Global<ExponentialRegexDataFlowConfig>;
/**
* An expression passed as the `input` to a call to a `Regex` method, where the regex appears to
* have exponential behavior.
*/
class ExponentialRegexSink extends DataFlow::ExprNode, Sink {
ExponentialRegexSink() {
exists(ExponentialRegexDataflow regexDataflow, RegexOperation regexOperation |
exists(RegexOperation regexOperation |
// Exponential regex flows to the pattern argument
regexDataflow.hasFlow(_, DataFlow::exprNode(regexOperation.getPattern()))
ExponentialRegexDataFlow::flow(_, DataFlow::exprNode(regexOperation.getPattern()))
|
// This is used as an input for this pattern
this.getExpr() = regexOperation.getInput() and

View File

@@ -26,9 +26,11 @@ abstract class Sink extends DataFlow::ExprNode { }
abstract class Sanitizer extends DataFlow::ExprNode { }
/**
* DEPRECATED: Use `TaintedPath` instead.
*
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "TaintedPath" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -38,6 +40,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
*/
private module TaintedPathConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A taint-tracking module for uncontrolled data in path expression vulnerabilities.
*/
module TaintedPath = TaintTracking::Global<TaintedPathConfig>;
/** A source of remote user input. */
class RemoteSource extends Source instanceof RemoteFlowSource { }

View File

@@ -75,9 +75,11 @@ class JsonConvertTrackingConfig extends TaintTracking::Configuration {
}
/**
* DEPRECATED: Use `TypeNameTracking` instead.
*
* Tracks unsafe `TypeNameHandling` setting to `JsonConvert` call
*/
class TypeNameTrackingConfig extends DataFlow::Configuration {
deprecated class TypeNameTrackingConfig extends DataFlow::Configuration {
TypeNameTrackingConfig() { this = "TypeNameTrackingConfig" }
override predicate isSource(DataFlow::Node source) {
@@ -127,6 +129,62 @@ class TypeNameTrackingConfig extends DataFlow::Configuration {
}
}
/**
* Configuration module for tracking unsafe `TypeNameHandling` setting to `JsonConvert` calls.
*/
private module TypeNameTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
(
source.asExpr() instanceof MemberConstantAccess and
source.getType() instanceof TypeNameHandlingEnum
or
source.asExpr() instanceof IntegerLiteral
) and
source.asExpr().hasValue() and
not source.asExpr().getValue() = "0"
}
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc, Method m, Expr expr |
m = mc.getTarget() and
(
not mc.getArgument(0).hasValue() and
m instanceof NewtonsoftJsonConvertClassDeserializeObjectMethod
) and
expr = mc.getAnArgument() and
sink.asExpr() = expr and
expr.getType() instanceof JsonSerializerSettingsClass
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
node1.asExpr() instanceof IntegerLiteral and
node2.asExpr().(CastExpr).getExpr() = node1.asExpr()
or
node1.getType() instanceof TypeNameHandlingEnum and
exists(PropertyWrite pw, Property p, Assignment a |
a.getLValue() = pw and
pw.getProperty() = p and
p.getDeclaringType() instanceof JsonSerializerSettingsClass and
p.hasName("TypeNameHandling") and
(
node1.asExpr() = a.getRValue() and
node2.asExpr() = pw.getQualifier()
or
exists(ObjectInitializer oi |
node1.asExpr() = oi.getAMemberInitializer().getRValue() and
node2.asExpr() = oi
)
)
)
}
}
/**
* Configuration module for tracking unsafe `TypeNameHandling` setting to `JsonConvert` calls.
*/
module TypeNameTracking = DataFlow::Global<TypeNameTrackingConfig>;
/**
* User input to static method or constructor call deserialization flow tracking.
*/

View File

@@ -33,9 +33,11 @@ abstract class Sanitizer extends DataFlow::ExprNode { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* DEPRECATED: Use `UrlRedirect` instead.
*
* A taint-tracking configuration for reasoning about unvalidated URL redirect vulnerabilities.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "UrlRedirect" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -49,6 +51,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
}
/**
* A taint-tracking configuration for reasoning about unvalidated URL redirect vulnerabilities.
*/
private module UrlRedirectConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A taint-tracking module for reasoning about unvalidated URL redirect vulnerabilities.
*/
module UrlRedirect = TaintTracking::Global<UrlRedirectConfig>;
/** A source of remote user input. */
class RemoteSource extends Source instanceof RemoteFlowSource { }

View File

@@ -44,9 +44,11 @@ private class InsecureXmlSink extends Sink {
abstract class Sanitizer extends DataFlow::Node { }
/**
* DEPRECATED: Use `XmlEntityInjection` instead.
*
* A taint-tracking configuration for untrusted user input used in XML processing.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "XMLInjection" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -61,6 +63,36 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
}
/**
* A taint-tracking configuration for untrusted user input used in XML processing.
*/
private module XmlEntityInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A taint-tracking module for untrusted user input used in XML processing.
*/
module XmlEntityInjection implements DataFlow::GlobalFlowSig {
import TaintTracking::Global<XmlEntityInjectionConfig> as Super
import Super
/**
* Holds if data can flow from `source` to `sink`.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate flowPath(XmlEntityInjection::PathNode source, XmlEntityInjection::PathNode sink) {
Super::flowPath(source, sink) and
exists(sink.getNode().(Sink).getReason())
}
}
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }

View File

@@ -24,9 +24,11 @@ abstract class Sink extends DataFlow::ExprNode { }
abstract class Sanitizer extends DataFlow::ExprNode { }
/**
* DEPRECATED: Use `XpathInjection` instead.
*
* A taint-tracking configuration for untrusted user input used in XPath expression.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "XPathInjection" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -36,6 +38,32 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A taint-tracking configuration for untrusted user input used in XPath expression.
*/
module XpathInjectionConfig implements DataFlow::ConfigSig {
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(DataFlow::Node source) { source instanceof Source }
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A taint-tracking module for untrusted user input used in XPath expression.
*/
module XpathInjection = TaintTracking::Global<XpathInjectionConfig>;
/** A source of remote user input. */
class RemoteSource extends Source instanceof RemoteFlowSource { }

View File

@@ -27,8 +27,12 @@ abstract class Sanitizer extends DataFlow::ExprNode { }
*/
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/** A taint tracking configuration for Zip Slip */
class TaintTrackingConfiguration extends TaintTracking::Configuration {
/**
* DEPRECATED: Use `ZipSlip` instead.
*
* A taint tracking configuration for Zip Slip.
*/
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "ZipSlipTaintTracking" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -42,6 +46,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
}
/**
* A taint tracking configuration for Zip Slip.
*/
private module ZipSlipConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A taint tracking module for Zip Slip.
*/
module ZipSlip = TaintTracking::Global<ZipSlipConfig>;
/** An access to the `FullName` property of a `ZipArchiveEntry`. */
class ArchiveFullNameSource extends Source {
ArchiveFullNameSource() {

View File

@@ -172,26 +172,24 @@ module XmlReader {
isNetFrameworkBefore(this.(MethodCall).getTarget().getDeclaringType(), "4.0")
or
// bad settings flow here
exists(SettingsDataFlowConfig flow, ObjectCreation settings |
flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
exists(ObjectCreation settings |
SettingsDataFlow::flow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
XmlSettings::dtdEnabledSettings(settings, evidence, reason)
)
}
private predicate insecureResolver(string reason, Expr evidence) {
// bad settings flow here
exists(SettingsDataFlowConfig flow, ObjectCreation settings |
flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
exists(ObjectCreation settings |
SettingsDataFlow::flow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
XmlSettings::insecureResolverSettings(settings, evidence, reason)
)
// default is secure
}
}
private class SettingsDataFlowConfig extends DataFlow2::Configuration {
SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" }
override predicate isSource(DataFlow::Node source) {
private module SettingsDataFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
// flow from places where we construct an XmlReaderSettings
source
.asExpr()
@@ -202,10 +200,12 @@ module XmlReader {
.hasQualifiedName("System.Xml", "XmlReaderSettings")
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(InsecureXmlReaderCreate create).getSettings()
}
}
private module SettingsDataFlow = DataFlow::Global<SettingsDataFlowConfig>;
}
/** Provides predicates related to `System.Xml.XmlTextReader`. */

View File

@@ -12,38 +12,36 @@
import csharp
import semmle.code.csharp.frameworks.Format
import DataFlow::PathGraph
import FormatInvalid::PathGraph
private class FormatConfiguration extends DataFlow::Configuration {
FormatConfiguration() { this = "format" }
module FormatInvalidConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
override predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
override predicate isSink(DataFlow::Node n) {
exists(FormatCall c | n.asExpr() = c.getFormatExpr())
}
predicate isSink(DataFlow::Node n) { exists(FormatCall c | n.asExpr() = c.getFormatExpr()) }
}
module FormatInvalid = DataFlow::Global<FormatInvalidConfig>;
private predicate invalidFormatString(
InvalidFormatString src, DataFlow::PathNode source, DataFlow::PathNode sink, string msg,
InvalidFormatString src, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
FormatCall call, string callString
) {
source.getNode().asExpr() = src and
sink.getNode().asExpr() = call.getFormatExpr() and
any(FormatConfiguration conf).hasFlowPath(source, sink) and
FormatInvalid::flowPath(source, sink) and
call.hasInsertions() and
msg = "Invalid format string used in $@ formatting call." and
callString = "this"
}
private predicate unusedArgument(
FormatCall call, DataFlow::PathNode source, DataFlow::PathNode sink, string msg,
FormatCall call, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
ValidFormatString src, string srcString, Expr unusedExpr, string unusedString
) {
exists(int unused |
source.getNode().asExpr() = src and
sink.getNode().asExpr() = call.getFormatExpr() and
any(FormatConfiguration conf).hasFlowPath(source, sink) and
FormatInvalid::flowPath(source, sink) and
unused = call.getASuppliedArgument() and
not unused = src.getAnInsert() and
not src.getValue() = "" and
@@ -55,13 +53,13 @@ private predicate unusedArgument(
}
private predicate missingArgument(
FormatCall call, DataFlow::PathNode source, DataFlow::PathNode sink, string msg,
FormatCall call, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
ValidFormatString src, string srcString
) {
exists(int used, int supplied |
source.getNode().asExpr() = src and
sink.getNode().asExpr() = call.getFormatExpr() and
any(FormatConfiguration conf).hasFlowPath(source, sink) and
FormatInvalid::flowPath(source, sink) and
used = src.getAnInsert() and
supplied = call.getSuppliedArguments() and
used >= supplied and
@@ -71,8 +69,8 @@ private predicate missingArgument(
}
from
Element alert, DataFlow::PathNode source, DataFlow::PathNode sink, string msg, Element extra1,
string extra1String, Element extra2, string extra2String
Element alert, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
Element extra1, string extra1String, Element extra2, string extra2String
where
invalidFormatString(alert, source, sink, msg, extra1, extra1String) and
extra2 = extra1 and

View File

@@ -24,10 +24,8 @@ private class ReturnNode extends DataFlow::ExprNode {
}
}
private class Conf extends DataFlow::Configuration {
Conf() { this = "NoDisposeCallOnLocalIDisposable" }
override predicate isSource(DataFlow::Node node) {
module DisposeCallOnLocalIDisposableConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
node.asExpr() =
any(LocalScopeDisposableCreation disposable |
// Only care about library types - user types often have spurious IDisposable declarations
@@ -37,7 +35,7 @@ private class Conf extends DataFlow::Configuration {
)
}
override predicate isSink(DataFlow::Node node) {
predicate isSink(DataFlow::Node node) {
// Things that return may be disposed elsewhere
node instanceof ReturnNode
or
@@ -80,23 +78,27 @@ private class Conf extends DataFlow::Configuration {
)
}
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
node2.asExpr() =
any(LocalScopeDisposableCreation other | other.getAnArgument() = node1.asExpr())
}
override predicate isBarrierOut(DataFlow::Node node) {
this.isSink(node) and
predicate isBarrierOut(DataFlow::Node node) {
isSink(node) and
not node instanceof ReturnNode
}
}
module DisposeCallOnLocalIDisposable = DataFlow::Global<DisposeCallOnLocalIDisposableConfig>;
/** Holds if `disposable` may not be disposed. */
predicate mayNotBeDisposed(LocalScopeDisposableCreation disposable) {
exists(Conf conf, DataFlow::ExprNode e |
exists(DataFlow::ExprNode e |
e.getExpr() = disposable and
conf.isSource(e) and
not exists(DataFlow::Node sink | conf.hasFlow(DataFlow::exprNode(disposable), sink) |
DisposeCallOnLocalIDisposableConfig::isSource(e) and
not exists(DataFlow::Node sink |
DisposeCallOnLocalIDisposable::flow(DataFlow::exprNode(disposable), sink)
|
sink instanceof ReturnNode
implies
sink.getEnclosingCallable() = disposable.getEnclosingCallable()

View File

@@ -37,19 +37,19 @@ predicate inForeachStmtBody(ForeachStmt loop, Element e) {
)
}
class LambdaDataFlowConfiguration extends DataFlow::Configuration {
LambdaDataFlowConfiguration() { this = "LambdaDataFlowConfiguration" }
module LambdaDataFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { lambdaCapturesLoopVariable(source.asExpr(), _, _) }
override predicate isSource(DataFlow::Node source) {
lambdaCapturesLoopVariable(source.asExpr(), _, _)
}
predicate isSink(DataFlow::Node sink) { exists(getAssignmentTarget(sink.asExpr())) }
}
override predicate isSink(DataFlow::Node sink) { exists(getAssignmentTarget(sink.asExpr())) }
module LambdaDataFlow {
private import DataFlow::Global<LambdaDataFlowConfig>
predicate capturesLoopVarAndIsStoredIn(
AnonymousFunctionExpr lambda, Variable loopVar, Element storage
) {
exists(DataFlow::Node sink | this.hasFlow(DataFlow::exprNode(lambda), sink) |
exists(DataFlow::Node sink | flow(DataFlow::exprNode(lambda), sink) |
storage = getAssignmentTarget(sink.asExpr())
) and
exists(ForeachStmt loop | lambdaCapturesLoopVariable(lambda, loop, loopVar) |
@@ -109,7 +109,7 @@ predicate declaredInsideLoop(ForeachStmt loop, LocalVariable v) {
)
}
from LambdaDataFlowConfiguration c, AnonymousFunctionExpr lambda, Variable loopVar, Element storage
where c.capturesLoopVarAndIsStoredIn(lambda, loopVar, storage)
from AnonymousFunctionExpr lambda, Variable loopVar, Element storage
where LambdaDataFlow::capturesLoopVarAndIsStoredIn(lambda, loopVar, storage)
select lambda, "Function which may be stored in $@ captures variable $@.", storage,
storage.toString(), loopVar, loopVar.getName()

View File

@@ -10,21 +10,17 @@
*/
import csharp
import DataFlow::PathGraph
import UnsafeYearCreationFromArithmetic::PathGraph
class UnsafeYearCreationFromArithmeticConfiguration extends TaintTracking::Configuration {
UnsafeYearCreationFromArithmeticConfiguration() {
this = "UnsafeYearCreationFromArithmeticConfiguration"
}
override predicate isSource(DataFlow::Node source) {
module UnsafeYearCreationFromArithmeticConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(ArithmeticOperation ao, PropertyAccess pa | ao = source.asExpr() |
pa = ao.getAChild*() and
pa.getProperty().hasQualifiedName("System.DateTime", "Year")
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(ObjectCreation oc |
sink.asExpr() = oc.getArgumentForName("year") and
oc.getObjectType().getABaseType*().hasQualifiedName("System", "DateTime")
@@ -32,10 +28,12 @@ class UnsafeYearCreationFromArithmeticConfiguration extends TaintTracking::Confi
}
}
module UnsafeYearCreationFromArithmetic =
TaintTracking::Global<UnsafeYearCreationFromArithmeticConfig>;
from
UnsafeYearCreationFromArithmeticConfiguration config, DataFlow::PathNode source,
DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
UnsafeYearCreationFromArithmetic::PathNode source, UnsafeYearCreationFromArithmetic::PathNode sink
where UnsafeYearCreationFromArithmetic::flowPath(source, sink)
select sink, source, sink,
"This $@ based on a 'System.DateTime.Year' property is used in a construction of a new 'System.DateTime' object, flowing to the 'year' argument.",
source, "arithmetic operation"

View File

@@ -18,21 +18,20 @@ import csharp
import ParallelSink
import ICryptoTransform
class NotThreadSafeCryptoUsageIntoParallelInvokeConfig extends TaintTracking::Configuration {
NotThreadSafeCryptoUsageIntoParallelInvokeConfig() {
this = "NotThreadSafeCryptoUsageIntoParallelInvokeConfig"
}
override predicate isSource(DataFlow::Node source) {
module NotThreadSafeCryptoUsageIntoParallelInvokeConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof LambdaCapturingICryptoTransformSource
}
override predicate isSink(DataFlow::Node sink) { sink instanceof ParallelSink }
predicate isSink(DataFlow::Node sink) { sink instanceof ParallelSink }
}
from Expr e, string m, LambdaExpr l, NotThreadSafeCryptoUsageIntoParallelInvokeConfig config
module NotThreadSafeCryptoUsageIntoParallelInvoke =
TaintTracking::Global<NotThreadSafeCryptoUsageIntoParallelInvokeConfig>;
from Expr e, string m, LambdaExpr l
where
config.hasFlow(DataFlow::exprNode(l), DataFlow::exprNode(e)) and
NotThreadSafeCryptoUsageIntoParallelInvoke::flow(DataFlow::exprNode(l), DataFlow::exprNode(e)) and
m =
"A $@ seems to be used to start a new thread is capturing a local variable that either implements 'System.Security.Cryptography.ICryptoTransform' or has a field of this type."
select e, m, l, "lambda expression"

View File

@@ -16,9 +16,9 @@
import csharp
import semmle.code.csharp.security.dataflow.TaintedPathQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import TaintedPath::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
from TaintedPath::PathNode source, TaintedPath::PathNode sink
where TaintedPath::flowPath(source, sink)
select sink.getNode(), source, sink, "This path depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -14,10 +14,10 @@
import csharp
import semmle.code.csharp.security.dataflow.ZipSlipQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import ZipSlip::PathGraph
from TaintTrackingConfiguration zipTaintTracking, DataFlow::PathNode source, DataFlow::PathNode sink
where zipTaintTracking.hasFlowPath(source, sink)
from ZipSlip::PathNode source, ZipSlip::PathNode sink
where ZipSlip::flowPath(source, sink)
select source.getNode(), source, sink,
"Unsanitized archive entry, which may contain '..', is used in a $@.", sink.getNode(),
"file system operation"

View File

@@ -12,19 +12,17 @@
*/
import csharp
import DataFlow::PathGraph
import semmle.code.csharp.security.dataflow.flowsources.Remote
import semmle.code.csharp.frameworks.system.Xml
import XmlInjection::PathGraph
/**
* A taint-tracking configuration for untrusted user input used in XML.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "XMLInjection" }
module XmlInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
mc.getTarget().hasName("WriteRaw") and
mc.getTarget().getDeclaringType().getABaseType*().hasQualifiedName("System.Xml", "XmlWriter")
@@ -33,7 +31,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
)
}
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
exists(MethodCall mc |
mc.getTarget().hasName("Escape") and
mc.getTarget()
@@ -46,7 +44,12 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
}
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
/**
* A taint-tracking module for untrusted user input used in XML.
*/
module XmlInjection = TaintTracking::Global<XmlInjectionConfig>;
from XmlInjection::PathNode source, XmlInjection::PathNode sink
where XmlInjection::flowPath(source, sink)
select sink.getNode(), source, sink, "This XML element depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -15,20 +15,18 @@
import csharp
import semmle.code.csharp.security.dataflow.flowsources.Remote
import semmle.code.csharp.commons.Util
import DataFlow::PathGraph
import AssemblyPathInjection::PathGraph
/**
* A taint-tracking configuration for untrusted user input used to load a DLL.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "DLLInjection" }
override predicate isSource(DataFlow::Node source) {
module AssemblyPathInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource or
source.asExpr() = any(MainMethod main).getParameter(0).getAnAccess()
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc, string name, int arg |
mc.getTarget().getName().matches(name) and
mc.getTarget()
@@ -48,7 +46,12 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
}
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
/**
* A taint-tracking module for untrusted user input used to load a DLL.
*/
module AssemblyPathInjection = TaintTracking::Global<AssemblyPathInjectionConfig>;
from AssemblyPathInjection::PathNode source, AssemblyPathInjection::PathNode sink
where AssemblyPathInjection::flowPath(source, sink)
select sink.getNode(), source, sink, "This assembly path depends on a $@.", source,
"user-provided value"

View File

@@ -15,29 +15,29 @@ import csharp
import semmle.code.csharp.security.dataflow.flowsources.Remote
import semmle.code.csharp.security.dataflow.flowsources.Local
import semmle.code.csharp.frameworks.Format
import DataFlow::PathGraph
import FormatString::PathGraph
class FormatStringConfiguration extends TaintTracking::Configuration {
FormatStringConfiguration() { this = "FormatStringConfiguration" }
override predicate isSource(DataFlow::Node source) {
module FormatStringConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource
or
source instanceof LocalFlowSource
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(FormatCall call | call.hasInsertions()).getFormatExpr()
}
}
module FormatString = TaintTracking::Global<FormatStringConfig>;
string getSourceType(DataFlow::Node node) {
result = node.(RemoteFlowSource).getSourceType()
or
result = node.(LocalFlowSource).getSourceType()
}
from FormatStringConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
from FormatString::PathNode source, FormatString::PathNode sink
where FormatString::flowPath(source, sink)
select sink.getNode(), source, sink, "This format string depends on $@.", source.getNode(),
("this" + getSourceType(source.getNode()))

View File

@@ -15,12 +15,10 @@ import semmle.code.csharp.security.SensitiveActions
import semmle.code.csharp.security.dataflow.flowsinks.Remote
import semmle.code.csharp.frameworks.system.data.Common
import semmle.code.csharp.frameworks.System
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import ExposureInTransmittedData::PathGraph
class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "Exposure through transmitted data" }
override predicate isSource(DataFlow::Node source) {
module ExposureInTransmittedDataConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
// `source` may contain a password
source.asExpr() instanceof PasswordExpr
or
@@ -42,10 +40,12 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
)
}
override predicate isSink(DataFlow::Node sink) { sink instanceof RemoteFlowSink }
predicate isSink(DataFlow::Node sink) { sink instanceof RemoteFlowSink }
}
from TaintTrackingConfiguration configuration, DataFlow::PathNode source, DataFlow::PathNode sink
where configuration.hasFlowPath(source, sink)
module ExposureInTransmittedData = TaintTracking::Global<ExposureInTransmittedDataConfig>;
from ExposureInTransmittedData::PathNode source, ExposureInTransmittedData::PathNode sink
where ExposureInTransmittedData::flowPath(source, sink)
select sink.getNode(), source, sink, "This data transmitted to the user depends on $@.",
source.getNode(), "sensitive information"

View File

@@ -16,15 +16,13 @@
import csharp
import semmle.code.csharp.frameworks.System
import semmle.code.csharp.security.dataflow.flowsinks.Remote
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import ExceptionInformationExposure::PathGraph
/**
* A taint-tracking configuration for reasoning about stack traces that flow to web page outputs.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "StackTrace" }
override predicate isSource(DataFlow::Node source) {
module ExceptionInformationExposureConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(Expr exceptionExpr |
// Writing an exception directly is bad
source.asExpr() = exceptionExpr
@@ -40,7 +38,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
)
}
override predicate isAdditionalTaintStep(DataFlow::Node source, DataFlow::Node sink) {
predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) {
sink.asExpr() =
any(MethodCall mc |
source.asExpr() = mc.getQualifier() and
@@ -49,20 +47,25 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
)
}
override predicate isSink(DataFlow::Node sink) { sink instanceof RemoteFlowSink }
predicate isSink(DataFlow::Node sink) { sink instanceof RemoteFlowSink }
override predicate isSanitizer(DataFlow::Node sanitizer) {
predicate isBarrier(DataFlow::Node sanitizer) {
// Do not flow through Message
sanitizer.asExpr() = any(SystemExceptionClass se).getProperty("Message").getAnAccess()
}
override predicate isSanitizerIn(DataFlow::Node sanitizer) {
predicate isBarrierIn(DataFlow::Node sanitizer) {
// Do not flow through Message
sanitizer.asExpr().getType().(RefType).getABaseType*() instanceof SystemExceptionClass
}
}
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
/**
* A taint-tracking module for reasoning about stack traces that flow to web page outputs.
*/
module ExceptionInformationExposure = TaintTracking::Global<ExceptionInformationExposureConfig>;
from ExceptionInformationExposure::PathNode source, ExceptionInformationExposure::PathNode sink
where ExceptionInformationExposure::flowPath(source, sink)
select sink.getNode(), source, sink, "This information exposed to the user depends on $@.",
source.getNode(), "exception information"

View File

@@ -12,12 +12,10 @@
import csharp
import semmle.code.csharp.dataflow.DataFlow::DataFlow
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import AddCertToRootStore::PathGraph
class AddCertToRootStoreConfig extends DataFlow::Configuration {
AddCertToRootStoreConfig() { this = "Adding Certificate To Root Store" }
override predicate isSource(DataFlow::Node source) {
module AddCertToRootStoreConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(ObjectCreation oc | oc = source.asExpr() |
oc.getType()
.(RefType)
@@ -26,7 +24,7 @@ class AddCertToRootStoreConfig extends DataFlow::Configuration {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
(
mc.getTarget()
@@ -40,6 +38,8 @@ class AddCertToRootStoreConfig extends DataFlow::Configuration {
}
}
from DataFlow::PathNode oc, DataFlow::PathNode mc, AddCertToRootStoreConfig config
where config.hasFlowPath(oc, mc)
module AddCertToRootStore = DataFlow::Global<AddCertToRootStoreConfig>;
from AddCertToRootStore::PathNode oc, AddCertToRootStore::PathNode mc
where AddCertToRootStore::flowPath(oc, mc)
select mc.getNode(), oc, mc, "This certificate is added to the root certificate store."

View File

@@ -11,15 +11,13 @@
*/
import csharp
import DataFlow::PathGraph
import InsecureSqlConnection::PathGraph
/**
* A data flow configuration for tracking strings passed to `SqlConnection[StringBuilder]` instances.
*/
class TaintTrackingConfiguration extends DataFlow::Configuration {
TaintTrackingConfiguration() { this = "TaintTrackingConfiguration" }
override predicate isSource(DataFlow::Node source) {
module InsecureSqlConnectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(string s | s = source.asExpr().(StringLiteral).getValue().toLowerCase() |
s.matches("%encrypt=false%")
or
@@ -27,7 +25,7 @@ class TaintTrackingConfiguration extends DataFlow::Configuration {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(ObjectCreation oc |
oc.getRuntimeArgument(0) = sink.asExpr() and
(
@@ -39,8 +37,13 @@ class TaintTrackingConfiguration extends DataFlow::Configuration {
}
}
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
/**
* A data flow configuration for tracking strings passed to `SqlConnection[StringBuilder]` instances.
*/
module InsecureSqlConnection = DataFlow::Global<InsecureSqlConnectionConfig>;
from InsecureSqlConnection::PathNode source, InsecureSqlConnection::PathNode sink
where InsecureSqlConnection::flowPath(source, sink)
select sink.getNode(), source, sink,
"$@ flows to this SQL connection and does not specify `Encrypt=True`.", source.getNode(),
"Connection string"

View File

@@ -48,12 +48,9 @@ where
)
or
// JsonConvert static method call, but with additional unsafe typename tracking
exists(
JsonConvertTrackingConfig taintTrackingJsonConvert, TypeNameTrackingConfig typenameTracking,
DataFlow::Node settingsCallArg
|
exists(JsonConvertTrackingConfig taintTrackingJsonConvert, DataFlow::Node settingsCallArg |
taintTrackingJsonConvert.hasFlowPath(userInput, deserializeCallArg) and
typenameTracking.hasFlow(_, settingsCallArg) and
TypeNameTracking::flow(_, settingsCallArg) and
deserializeCallArg.getNode().asExpr().getParent() = settingsCallArg.asExpr().getParent()
)
select deserializeCallArg, userInput, deserializeCallArg, "$@ flows to unsafe deserializer.",

View File

@@ -13,9 +13,9 @@
import csharp
import semmle.code.csharp.security.dataflow.UrlRedirectQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import UrlRedirect::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
from UrlRedirect::PathNode source, UrlRedirect::PathNode sink
where UrlRedirect::flowPath(source, sink)
select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source.getNode(),
"user-provided value"

View File

@@ -14,10 +14,10 @@
import csharp
import semmle.code.csharp.security.dataflow.XMLEntityInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import XmlEntityInjection::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
from XmlEntityInjection::PathNode source, XmlEntityInjection::PathNode sink
where XmlEntityInjection::flowPath(source, sink)
select sink.getNode(), source, sink,
"This insecure XML processing depends on a $@ (" + sink.getNode().(Sink).getReason() + ").",
source.getNode(), "user-provided value"

View File

@@ -13,14 +13,20 @@
import csharp
import semmle.code.csharp.security.dataflow.flowsources.Stored
import semmle.code.csharp.security.dataflow.XPathInjectionQuery as XPathInjection
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import semmle.code.csharp.security.dataflow.XPathInjectionQuery
import StoredXpathInjection::PathGraph
class StoredTaintTrackingConfiguration extends XPathInjection::TaintTrackingConfiguration {
override predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource }
module StoredXpathInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource }
predicate isSink = XpathInjectionConfig::isSink/1;
predicate isBarrier = XpathInjectionConfig::isBarrier/1;
}
from StoredTaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
module StoredXpathInjection = TaintTracking::Global<StoredXpathInjectionConfig>;
from StoredXpathInjection::PathNode source, StoredXpathInjection::PathNode sink
where StoredXpathInjection::flowPath(source, sink)
select sink.getNode(), source, sink, "This XPath expression depends on a $@.", source.getNode(),
"stored (potentially user-provided) value"

View File

@@ -13,9 +13,9 @@
import csharp
import semmle.code.csharp.security.dataflow.XPathInjectionQuery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import XpathInjection::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
from XpathInjection::PathNode source, XpathInjection::PathNode sink
where XpathInjection::flowPath(source, sink)
select sink.getNode(), source, sink, "This XPath expression depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -14,7 +14,7 @@
import csharp
import semmle.code.csharp.frameworks.Test
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import Random::InsecureRandomness::PathGraph
module Random {
import semmle.code.csharp.security.dataflow.flowsources.Remote
@@ -38,21 +38,24 @@ module Random {
/**
* A taint-tracking configuration for insecure randomness in security sensitive context.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "RandomDataFlowConfiguration" }
module InsecureRandomnessConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
// succ = array_or_indexer[pred] - use of random numbers in an index
succ.asExpr().(ElementAccess).getAnIndex() = pred.asExpr()
}
}
/**
* A taint-tracking module for insecure randomness in security sensitive context.
*/
module InsecureRandomness = TaintTracking::Global<InsecureRandomnessConfig>;
/** A source of cryptographically insecure random numbers. */
class RandomSource extends Source {
RandomSource() {
@@ -112,10 +115,8 @@ module Random {
}
}
from
Random::TaintTrackingConfiguration randomTracking, DataFlow::PathNode source,
DataFlow::PathNode sink
where randomTracking.hasFlowPath(source, sink)
from Random::InsecureRandomness::PathNode source, Random::InsecureRandomness::PathNode sink
where Random::InsecureRandomness::flowPath(source, sink)
select sink.getNode(), source, sink,
"This uses a cryptographically insecure random number generated at $@ in a security context.",
source.getNode(), source.getNode().toString()

View File

@@ -16,9 +16,9 @@
import csharp
import TaintedWebClientLib
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import TaintedWebClient::PathGraph
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
from TaintedWebClient::PathNode source, TaintedWebClient::PathNode sink
where TaintedWebClient::flowPath(source, sink)
select sink.getNode(), source, sink, "A method of WebClient depepends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -38,9 +38,11 @@ abstract class Sink extends DataFlow::ExprNode { }
abstract class Sanitizer extends DataFlow::ExprNode { }
/**
* DEPRECATED: Use `TaintedWebClient` instead.
*
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() { this = "TaintedWebClientLib" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -50,6 +52,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
*/
private module TaintedWebClientConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A taint-tracking module for uncontrolled data in path expression vulnerabilities.
*/
module TaintedWebClient = TaintTracking::Global<TaintedWebClientConfig>;
/** A source of remote user input. */
class RemoteSource extends Source instanceof RemoteFlowSource { }

View File

@@ -12,9 +12,9 @@
import csharp
import RequestForgery::RequestForgery
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import RequestForgeryFlow::PathGraph
from RequestForgeryConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
from RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink
where RequestForgeryFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "The URL of this request depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -24,9 +24,11 @@ module RequestForgery {
abstract private class Barrier extends DataFlow::Node { }
/**
* DEPRECATED: Use `RequestForgeryFlow` instead.
*
* A data flow configuration for detecting server side request forgery vulnerabilities.
*/
class RequestForgeryConfiguration extends DataFlow::Configuration {
deprecated class RequestForgeryConfiguration extends DataFlow::Configuration {
RequestForgeryConfiguration() { this = "Server Side Request forgery" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -54,6 +56,40 @@ module RequestForgery {
override predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
}
/**
* A data flow configuration for detecting server side request forgery vulnerabilities.
*/
private module RequestForgeryFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) {
interpolatedStringFlowStep(prev, succ)
or
stringReplaceStep(prev, succ)
or
uriCreationStep(prev, succ)
or
formatConvertStep(prev, succ)
or
toStringStep(prev, succ)
or
stringConcatStep(prev, succ)
or
stringFormatStep(prev, succ)
or
pathCombineStep(prev, succ)
}
predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
}
/**
* A data flow module for detecting server side request forgery vulnerabilities.
*/
module RequestForgeryFlow = DataFlow::Global<RequestForgeryFlowConfig>;
/**
* A remote data flow source taken as a source
* for Server Side Request Forgery(SSRF) Vulnerabilities.

View File

@@ -36,13 +36,10 @@ where
iResponse.getAppendMethod() = mc.getTarget() and
isCookieWithSensitiveName(mc.getArgument(0)) and
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
not exists(OnAppendCookieHttpOnlyTrackingConfig config | config.hasFlowTo(_)) and
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
// Passed as third argument to `IResponseCookies.Append`
exists(
CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation,
DataFlow::Node append
|
cookieTracking.hasFlow(creation, append) and
exists(DataFlow::Node creation, DataFlow::Node append |
CookieOptionsTracking::flow(creation, append) and
creation.asExpr() = oc and
append.asExpr() = mc.getArgument(2)
)
@@ -70,7 +67,7 @@ where
// default is not configured or is not set to `Always`
not getAValueForCookiePolicyProp("HttpOnly").getValue() = "1" and
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
not exists(OnAppendCookieHttpOnlyTrackingConfig config | config.hasFlowTo(_)) and
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
iResponse.getAppendMethod() = mc.getTarget() and
isCookieWithSensitiveName(mc.getArgument(0)) and
(
@@ -79,8 +76,8 @@ where
oc = c and
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
not isPropertySet(oc, "HttpOnly") and
exists(CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation |
cookieTracking.hasFlow(creation, _) and
exists(DataFlow::Node creation |
CookieOptionsTracking::flow(creation, _) and
creation.asExpr() = oc
)
)

View File

@@ -30,15 +30,15 @@ where
getAValueForCookiePolicyProp("Secure").getValue() = "1"
) and
// there is no callback `OnAppendCookie` that sets `Secure` to true
not exists(OnAppendCookieSecureTrackingConfig config | config.hasFlowTo(_)) and
not OnAppendCookieSecureTracking::flowTo(_) and
(
// `Secure` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set
exists(ObjectCreation oc |
oc = c and
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
not isPropertySet(oc, "Secure") and
exists(CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation |
cookieTracking.hasFlow(creation, _) and
exists(DataFlow::Node creation |
CookieOptionsTracking::flow(creation, _) and
creation.asExpr() = oc
)
)
@@ -80,10 +80,10 @@ where
or
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
// there is no callback `OnAppendCookie` that sets `Secure` to true
not exists(OnAppendCookieSecureTrackingConfig config | config.hasFlowTo(_)) and
not OnAppendCookieSecureTracking::flowTo(_) and
// the cookie option is passed to `Append`
exists(CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation |
cookieTracking.hasFlow(creation, _) and
exists(DataFlow::Node creation |
CookieOptionsTracking::flow(creation, _) and
creation.asExpr() = oc
)
)

View File

@@ -12,7 +12,7 @@
import csharp
import semmle.code.csharp.dataflow.DataFlow2
import semmle.code.csharp.dataflow.TaintTracking2
import DataFlow::PathGraph
import HashWithoutSalt::PathGraph
/** The C# class `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. */
class HashAlgorithmProvider extends RefType {
@@ -120,12 +120,10 @@ predicate hasHashAncestor(MethodCall mc) {
* Taint configuration tracking flow from an expression whose name suggests it holds
* password data to a method call that generates a hash without a salt.
*/
class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" }
module HashWithoutSaltConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr }
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
sink.asExpr() = mc.getArgument(0) and
isHashCall(mc) and
@@ -148,7 +146,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
)
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodCall mc |
mc.getTarget()
.hasQualifiedName("Windows.Security.Cryptography", "CryptographicBuffer",
@@ -166,7 +164,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
* `byte[] saltedPassword = sha256.ComputeHash(rawSalted);`
* Or the password is concatenated with a salt as a string.
*/
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
exists(MethodCall mc |
hasFurtherProcessing(mc) and
mc.getAnArgument() = node.asExpr()
@@ -194,7 +192,9 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration c
where c.hasFlowPath(source, sink)
module HashWithoutSalt = TaintTracking::Global<HashWithoutSaltConfig>;
from HashWithoutSalt::PathNode source, HashWithoutSalt::PathNode sink
where HashWithoutSalt::flowPath(source, sink)
select sink.getNode(), source, sink, "$@ is hashed without a salt.", source.getNode(),
"The password"

View File

@@ -19,9 +19,11 @@ class TokenValidationParametersPropertySensitiveValidation extends Property {
}
/**
* DEPRECATED: Use `FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation` instead.
*
* A dataflow from a `false` value to a write sensitive property for `TokenValidationParameters`.
*/
class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation extends DataFlow::Configuration
deprecated class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation extends DataFlow::Configuration
{
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation() {
this = "FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation"
@@ -37,6 +39,25 @@ class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation
}
}
/**
* A dataflow configuration from a `false` value to a write sensitive property for `TokenValidationParameters`.
*/
private module FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidationConfig
implements DataFlow::ConfigSig
{
predicate isSource(DataFlow::Node source) {
source.asExpr().getValue() = "false" and
source.asExpr().getType() instanceof BoolType
}
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(TokenValidationParametersPropertySensitiveValidation p).getAnAssignedValue()
}
}
module FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation =
DataFlow::Global<FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidationConfig>;
/**
* Holds if `assemblyName` is older than version `ver`
*/
@@ -81,21 +102,6 @@ private class TokenValidationResultIsValidCall extends PropertyRead {
}
}
/**
* Dataflow from the output of `Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateToken` call to access the `IsValid` or `Exception` property
*/
private class FlowsToTokenValidationResultIsValidCall extends DataFlow::Configuration {
FlowsToTokenValidationResultIsValidCall() { this = "FlowsToTokenValidationResultIsValidCall" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof JsonWebTokenHandlerValidateTokenCall
}
override predicate isSink(DataFlow::Node sink) {
exists(TokenValidationResultIsValidCall call | sink.asExpr() = call.getQualifier())
}
}
/**
* A security-sensitive property for `Microsoft.IdentityModel.Tokens.TokenValidationParameters`
*/

View File

@@ -16,11 +16,10 @@ import JsonWebTokenHandlerLib
import semmle.code.csharp.commons.QualifiedName
from
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation config,
DataFlow::Node source, DataFlow::Node sink,
TokenValidationParametersPropertySensitiveValidation pw, string qualifier, string name
where
config.hasFlow(source, sink) and
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation::flow(source, sink) and
sink.asExpr() = pw.getAnAssignedValue() and
pw.hasQualifiedName(qualifier, name)
select sink, "The security sensitive property $@ is being disabled by the following value: $@.", pw,

View File

@@ -31,16 +31,16 @@ predicate unsafeDataContractTypeCreation(Expr e) {
e.(TypeofExpr).getTypeAccess().getTarget() instanceof DataSetOrTableRelatedClass
}
class Conf extends DataFlow::Configuration {
Conf() { this = "FlowToDataSerializerConstructor" }
module FlowToDataSerializerConstructorConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) }
override predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) }
override predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) }
predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) }
}
from Conf conf, DataFlow::Node source, DataFlow::Node sink
where conf.hasFlow(source, sink)
module FlowToDataSerializerConstructor = DataFlow::Global<FlowToDataSerializerConstructorConfig>;
from DataFlow::Node source, DataFlow::Node sink
where FlowToDataSerializerConstructor::flow(source, sink)
select sink,
"Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source.",
source, source.toString()

View File

@@ -11,23 +11,17 @@
*/
import csharp
import DataFlow::PathGraph
import experimental.code.csharp.Cryptography.NonCryptographicHashes
import DataFlowFromMethodToHash::PathGraph
class DataFlowFromMethodToHash extends TaintTracking::Configuration {
DataFlowFromMethodToHash() { this = "DataFlowFromMethodNameToHashFunction" }
module DataFlowFromMethodToHashConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSuspiciousPropertyName(source.asExpr()) }
/**
* Holds if `source` is a relevant data flow source.
*/
override predicate isSource(DataFlow::Node source) { isSuspiciousPropertyName(source.asExpr()) }
/**
* Holds if `sink` is a relevant data flow sink.
*/
override predicate isSink(DataFlow::Node sink) { isGetHash(sink.asExpr()) }
predicate isSink(DataFlow::Node sink) { isGetHash(sink.asExpr()) }
}
module DataFlowFromMethodToHash = TaintTracking::Global<DataFlowFromMethodToHashConfig>;
predicate isGetHash(Expr arg) {
exists(MethodCall mc |
(
@@ -48,8 +42,8 @@ predicate isSuspiciousPropertyName(PropertyRead pr) {
pr.getTarget().hasQualifiedName("System.Diagnostics", "Process", "ProcessName")
}
from DataFlow::PathNode src, DataFlow::PathNode sink, DataFlowFromMethodToHash conf
where conf.hasFlow(src.getNode(), sink.getNode())
from DataFlowFromMethodToHash::PathNode src, DataFlowFromMethodToHash::PathNode sink
where DataFlowFromMethodToHash::flow(src.getNode(), sink.getNode())
select src.getNode(), src, sink,
"The hash is calculated on $@, may be related to a backdoor. Please review the code for possible malicious intent.",
sink.getNode(), "this process name"

View File

@@ -9,18 +9,16 @@ import semmle.code.csharp.frameworks.microsoft.AspNetCore
* Holds if the expression is a variable with a sensitive name.
*/
predicate isCookieWithSensitiveName(Expr cookieExpr) {
exists(AuthCookieNameConfiguration dataflow, DataFlow::Node sink |
dataflow.hasFlowTo(sink) and
exists(DataFlow::Node sink |
AuthCookieName::flowTo(sink) and
sink.asExpr() = cookieExpr
)
}
/**
* Tracks if a variable with a sensitive name is used as an argument.
* Configuration for tracking if a variable with a sensitive name is used as an argument.
*/
private class AuthCookieNameConfiguration extends DataFlow::Configuration {
AuthCookieNameConfiguration() { this = "AuthCookieNameConfiguration" }
private module AuthCookieNameConfig implements DataFlow::ConfigSig {
private predicate isAuthVariable(Expr expr) {
exists(string val |
(
@@ -32,17 +30,22 @@ private class AuthCookieNameConfiguration extends DataFlow::Configuration {
)
}
override predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
override predicate isSink(DataFlow::Node sink) {
exists(Call c | sink.asExpr() = c.getAnArgument())
}
predicate isSink(DataFlow::Node sink) { exists(Call c | sink.asExpr() = c.getAnArgument()) }
}
/**
* Tracks if a variable with a sensitive name is used as an argument.
*/
private module AuthCookieName = DataFlow::Global<AuthCookieNameConfig>;
/**
* DEPRECATED: Use `CookieOptionsTracking` instead.
*
* Tracks creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)` call as a third parameter.
*/
class CookieOptionsTrackingConfiguration extends DataFlow::Configuration {
deprecated class CookieOptionsTrackingConfiguration extends DataFlow::Configuration {
CookieOptionsTrackingConfiguration() { this = "CookieOptionsTrackingConfiguration" }
override predicate isSource(DataFlow::Node source) {
@@ -57,6 +60,29 @@ class CookieOptionsTrackingConfiguration extends DataFlow::Configuration {
}
}
/**
* Configuration module tracking creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)`
* calls as a third parameter.
*/
private module CookieOptionsTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(ObjectCreation).getType() instanceof MicrosoftAspNetCoreHttpCookieOptions
}
predicate isSink(DataFlow::Node sink) {
exists(MicrosoftAspNetCoreHttpResponseCookies iResponse, MethodCall mc |
iResponse.getAppendMethod() = mc.getTarget() and
mc.getArgument(2) = sink.asExpr()
)
}
}
/**
* Tracking creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)`
* calls as a third parameter.
*/
module CookieOptionsTracking = DataFlow::Global<CookieOptionsTrackingConfig>;
/**
* Looks for property value of `CookiePolicyOptions` passed to `app.UseCookiePolicy` in `Startup.Configure`.
*/
@@ -109,18 +135,22 @@ Expr getAValueForProp(ObjectCreation create, Assignment a, string prop) {
predicate isPropertySet(ObjectCreation oc, string prop) { exists(getAValueForProp(oc, _, prop)) }
/**
* DEPRECATED: Use `OnAppendCookieSecureTracking` instead.
*
* Tracks if a callback used in `OnAppendCookie` sets `Secure` to `true`.
*/
class OnAppendCookieSecureTrackingConfig extends OnAppendCookieTrackingConfig {
deprecated class OnAppendCookieSecureTrackingConfig extends OnAppendCookieTrackingConfig {
OnAppendCookieSecureTrackingConfig() { this = "OnAppendCookieSecureTrackingConfig" }
override string propertyName() { result = "Secure" }
}
/**
* DEPRECATED: Use `OnAppendCookieHttpOnlyTracking` instead.
*
* Tracks if a callback used in `OnAppendCookie` sets `HttpOnly` to `true`.
*/
class OnAppendCookieHttpOnlyTrackingConfig extends OnAppendCookieTrackingConfig {
deprecated class OnAppendCookieHttpOnlyTrackingConfig extends OnAppendCookieTrackingConfig {
OnAppendCookieHttpOnlyTrackingConfig() { this = "OnAppendCookieHttpOnlyTrackingConfig" }
override string propertyName() { result = "HttpOnly" }
@@ -180,3 +210,83 @@ abstract private class OnAppendCookieTrackingConfig extends DataFlow::Configurat
)
}
}
private signature string propertyName();
/**
* Configuration for tracking if a callback used in `OnAppendCookie` sets a cookie property to `true`.
*/
private module OnAppendCookieTrackingConfig<propertyName/0 getPropertyName> implements
DataFlow::ConfigSig
{
/**
* Specifies the cookie property name to track.
*/
predicate isSource(DataFlow::Node source) {
exists(PropertyWrite pw, Assignment delegateAssign, Callable c |
pw.getProperty().getName() = "OnAppendCookie" and
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreBuilderCookiePolicyOptions and
delegateAssign.getLValue() = pw and
(
exists(LambdaExpr lambda |
delegateAssign.getRValue() = lambda and
lambda = c
)
or
exists(DelegateCreation delegate |
delegateAssign.getRValue() = delegate and
delegate.getArgument().(CallableAccess).getTarget() = c
)
) and
c.getParameter(0) = source.asParameter()
)
}
predicate isSink(DataFlow::Node sink) {
exists(PropertyWrite pw, Assignment a |
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
pw.getProperty().getName() = getPropertyName() and
a.getLValue() = pw and
exists(Expr val |
DataFlow::localExprFlow(val, a.getRValue()) and
val.getValue() = "true"
) and
sink.asExpr() = pw.getQualifier()
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
node2.asExpr() =
any(PropertyRead pr |
pr.getQualifier() = node1.asExpr() and
pr.getProperty().getDeclaringType() instanceof
MicrosoftAspNetCoreCookiePolicyAppendCookieContext
)
}
}
private string getPropertyNameSecure() { result = "Secure" }
/**
* Configuration module for tracking if a callback used in `OnAppendCookie` sets `Secure` to `true`.
*/
private module OnAppendCookieSecureTrackingConfig =
OnAppendCookieTrackingConfig<getPropertyNameSecure/0>;
/**
* Tracks if a callback used in `OnAppendCookie` sets `Secure` to `true`.
*/
module OnAppendCookieSecureTracking = DataFlow::Global<OnAppendCookieSecureTrackingConfig>;
private string getPropertyNameHttpOnly() { result = "HttpOnly" }
/**
* Configuration module for tracking if a callback used in `OnAppendCookie` sets `HttpOnly` to `true`.
*/
private module OnAppendCookieHttpOnlyTrackingConfig =
OnAppendCookieTrackingConfig<getPropertyNameHttpOnly/0>;
/**
* Tracks if a callback used in `OnAppendCookie` sets `HttpOnly` to `true`.
*/
module OnAppendCookieHttpOnlyTracking = DataFlow::Global<OnAppendCookieHttpOnlyTrackingConfig>;

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