mirror of
https://github.com/github/codeql.git
synced 2026-05-30 02:51:24 +02:00
Compare commits
329 Commits
jeongsoole
...
alexet/rub
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31a2e37418 | ||
|
|
60cc63f4d4 | ||
|
|
51229a6b48 | ||
|
|
9d37597461 | ||
|
|
e4b7b914b2 | ||
|
|
8f5a2a9e29 | ||
|
|
401281331f | ||
|
|
96bd9a96e5 | ||
|
|
c2f2522262 | ||
|
|
ef4c921b5a | ||
|
|
3d38d77d63 | ||
|
|
4709eacbf8 | ||
|
|
3fa563b293 | ||
|
|
2388dd06d4 | ||
|
|
7531a95d22 | ||
|
|
e903d76fa0 | ||
|
|
f5438390d5 | ||
|
|
98ec3753fd | ||
|
|
5f9dd75d7d | ||
|
|
4bb829ebec | ||
|
|
2de4a01c86 | ||
|
|
c6cc4c0e13 | ||
|
|
a02bf182c5 | ||
|
|
9db38bcb23 | ||
|
|
fecad025de | ||
|
|
fa7942393d | ||
|
|
3001d0bd1c | ||
|
|
3fcd46ec6c | ||
|
|
933e01b3d4 | ||
|
|
7da1ade835 | ||
|
|
b06491125e | ||
|
|
c608a9056b | ||
|
|
a99556e021 | ||
|
|
c70fd6a58c | ||
|
|
d37787c4ae | ||
|
|
3fc9da7466 | ||
|
|
169ae19015 | ||
|
|
a2836f5aab | ||
|
|
27222499d4 | ||
|
|
fc1fd263df | ||
|
|
0d34837eaf | ||
|
|
1afe67ab13 | ||
|
|
34e0a7b23a | ||
|
|
29d369f22f | ||
|
|
0d21fa51f2 | ||
|
|
3f23212d4e | ||
|
|
2ad5e20e79 | ||
|
|
4cb1e7840f | ||
|
|
a36fc30d44 | ||
|
|
24feb51661 | ||
|
|
163a403065 | ||
|
|
abea647bb1 | ||
|
|
08aad90346 | ||
|
|
f255fc2fd5 | ||
|
|
774b1820c2 | ||
|
|
73bae1627b | ||
|
|
ae54c62001 | ||
|
|
b8f85b3f29 | ||
|
|
aea676df3c | ||
|
|
f5903eaf2d | ||
|
|
fcecc5a3af | ||
|
|
6712cce1d7 | ||
|
|
ee83ca9125 | ||
|
|
09dc3c88b3 | ||
|
|
a94cffa27e | ||
|
|
6c9f248fdb | ||
|
|
0836f0b413 | ||
|
|
7494eac35c | ||
|
|
3449a34018 | ||
|
|
20a012d5f1 | ||
|
|
1c863b1bd4 | ||
|
|
c3c18bdbd2 | ||
|
|
9d2eb3d9b8 | ||
|
|
510df38da2 | ||
|
|
4cc9c24940 | ||
|
|
b3dc7a21b3 | ||
|
|
2b6e428c37 | ||
|
|
014e7dc4bc | ||
|
|
14bdc1ab22 | ||
|
|
0c0e1d0c46 | ||
|
|
eb4711e884 | ||
|
|
6a5ce39930 | ||
|
|
5faaa4f0f3 | ||
|
|
05dc9b6d34 | ||
|
|
60d26e522e | ||
|
|
82cf472f8a | ||
|
|
ffd6b2677c | ||
|
|
a50167812d | ||
|
|
f1b4e05579 | ||
|
|
e51cb478af | ||
|
|
cd01bd0e07 | ||
|
|
d3282a9470 | ||
|
|
a2944cdb61 | ||
|
|
9160036e41 | ||
|
|
7c98fa87da | ||
|
|
402a84f755 | ||
|
|
bf8cdffffa | ||
|
|
08fcf6114f | ||
|
|
6678dc490a | ||
|
|
a69a56122f | ||
|
|
a7ddfe2e89 | ||
|
|
6cc3c820b4 | ||
|
|
c96003f265 | ||
|
|
133e8d4897 | ||
|
|
3838a7b0d6 | ||
|
|
c16be43f15 | ||
|
|
5334e90717 | ||
|
|
c66ec63333 | ||
|
|
8f36624171 | ||
|
|
ab3f62eed1 | ||
|
|
891b2b8335 | ||
|
|
8fab235d66 | ||
|
|
14ede4e0c5 | ||
|
|
4e3ac93f70 | ||
|
|
089ef1cae1 | ||
|
|
48b95f3a4e | ||
|
|
fbf3d7c195 | ||
|
|
cd59ce5b04 | ||
|
|
64371688d7 | ||
|
|
64e40715ee | ||
|
|
c6077947a7 | ||
|
|
d0510bc672 | ||
|
|
529128cbde | ||
|
|
a57f4a1022 | ||
|
|
e03f57da9b | ||
|
|
b8c3b43cc4 | ||
|
|
b558e844ff | ||
|
|
986c8e1aec | ||
|
|
0c6e124b01 | ||
|
|
1135fbe950 | ||
|
|
1d8a57e7da | ||
|
|
e956d041dc | ||
|
|
a7ebe4a51a | ||
|
|
0066f74d3f | ||
|
|
7339dd0077 | ||
|
|
ac72abd3a6 | ||
|
|
c19291be88 | ||
|
|
314f1ff93f | ||
|
|
56670c66f1 | ||
|
|
f5a36566d1 | ||
|
|
19f86fd67f | ||
|
|
49ff967465 | ||
|
|
e56519d959 | ||
|
|
310c02f1fb | ||
|
|
a857069345 | ||
|
|
c781f98bdc | ||
|
|
228c45aaf8 | ||
|
|
7231f53b6e | ||
|
|
0691cd3e9a | ||
|
|
1533d7a4cc | ||
|
|
c7026c03df | ||
|
|
d600eb42cf | ||
|
|
4042081539 | ||
|
|
0a0be41527 | ||
|
|
94632931ba | ||
|
|
09d473674b | ||
|
|
7481de75cb | ||
|
|
c08525ad81 | ||
|
|
5694f029de | ||
|
|
f59ef58c1f | ||
|
|
16ed8476ce | ||
|
|
566b3dd8d9 | ||
|
|
d0287e9496 | ||
|
|
09dc7fc5c4 | ||
|
|
bce5f2539f | ||
|
|
37bc2bf5b3 | ||
|
|
dc1b4fcf7a | ||
|
|
be2017621f | ||
|
|
060d5152c4 | ||
|
|
674800748b | ||
|
|
4d2f2b89e7 | ||
|
|
54f0eed2c6 | ||
|
|
557f468fc0 | ||
|
|
82736ea621 | ||
|
|
1f308ee47a | ||
|
|
5c9218fe5a | ||
|
|
c6d95ceeb0 | ||
|
|
3aed1c8696 | ||
|
|
f3e0cfd947 | ||
|
|
f64e86fe2e | ||
|
|
d5bc95daeb | ||
|
|
16fc8c3d9e | ||
|
|
93f8cea884 | ||
|
|
c9ce6c0fb6 | ||
|
|
bd3155ef0c | ||
|
|
a44bdf3be2 | ||
|
|
0fc1ae272e | ||
|
|
ca5f8b0c1d | ||
|
|
499d224c2b | ||
|
|
d8eafbb9e2 | ||
|
|
775197372c | ||
|
|
07641e48ab | ||
|
|
cd47379700 | ||
|
|
607a1e46da | ||
|
|
c80588cda1 | ||
|
|
83617e099f | ||
|
|
6ecaf65132 | ||
|
|
27c7bf3047 | ||
|
|
2b1b90ccc4 | ||
|
|
dd2f53f42e | ||
|
|
9c87ad8293 | ||
|
|
7f24a2557d | ||
|
|
8ffe4d6593 | ||
|
|
ecd80fbc34 | ||
|
|
a7a887c828 | ||
|
|
b0f73f1cbd | ||
|
|
70a5ec5607 | ||
|
|
5de2c938d8 | ||
|
|
be5de9c080 | ||
|
|
ed2a832a55 | ||
|
|
fe055ad603 | ||
|
|
c293f03b9e | ||
|
|
a195d074c9 | ||
|
|
d724874969 | ||
|
|
e4420f63fb | ||
|
|
6725cb5b8c | ||
|
|
ed4864edf7 | ||
|
|
f542956f66 | ||
|
|
bb91df8145 | ||
|
|
59e1cbcc7b | ||
|
|
ef32a036b1 | ||
|
|
17aa5220a6 | ||
|
|
565cb434fc | ||
|
|
359525b65a | ||
|
|
8c0b0c4800 | ||
|
|
ec9d15bb79 | ||
|
|
2ce01bfb9a | ||
|
|
eb059969e3 | ||
|
|
ac798f2bc6 | ||
|
|
ac3675bdac | ||
|
|
219476cee0 | ||
|
|
ce3eabf05a | ||
|
|
5a8bffac11 | ||
|
|
1fd7643ab3 | ||
|
|
7b7ed61beb | ||
|
|
fdd09a4dbf | ||
|
|
28ccc83346 | ||
|
|
2d32c366d8 | ||
|
|
adeaceb7af | ||
|
|
49cf1739a4 | ||
|
|
1958c192ec | ||
|
|
b9d0abda63 | ||
|
|
a2fe19af38 | ||
|
|
69429a3e02 | ||
|
|
697c9f0bb0 | ||
|
|
66a60296b8 | ||
|
|
50507586ac | ||
|
|
ac96649a02 | ||
|
|
bec69ca106 | ||
|
|
9cd0340d21 | ||
|
|
e9c3e14fab | ||
|
|
fb7c003398 | ||
|
|
9278a41578 | ||
|
|
b695641362 | ||
|
|
d18dac0c8e | ||
|
|
63aaebbea6 | ||
|
|
95607c5f31 | ||
|
|
8a7671dc2a | ||
|
|
71eae39feb | ||
|
|
c98e6d7c56 | ||
|
|
a9458ba762 | ||
|
|
d988afd4a4 | ||
|
|
7757279908 | ||
|
|
44b1e921d6 | ||
|
|
085e8d40fd | ||
|
|
f69b057893 | ||
|
|
ae574f7cf2 | ||
|
|
f72efa638a | ||
|
|
c83cb533ce | ||
|
|
036035b6a2 | ||
|
|
fe52351aed | ||
|
|
73368ea59a | ||
|
|
0672027822 | ||
|
|
451808616e | ||
|
|
bd07b8a4c7 | ||
|
|
6a4659fc7e | ||
|
|
3316d6135d | ||
|
|
d99812a10d | ||
|
|
64241caf1d | ||
|
|
bac0a635f9 | ||
|
|
47affa0fed | ||
|
|
cf72fde911 | ||
|
|
32d29ffde3 | ||
|
|
b9bd199432 | ||
|
|
6083df2b7f | ||
|
|
de3ff45cba | ||
|
|
cce5f24b38 | ||
|
|
8865d89fe9 | ||
|
|
2ee1681126 | ||
|
|
14cb2bb12f | ||
|
|
076f53147d | ||
|
|
627790f98b | ||
|
|
cf33cf7653 | ||
|
|
0354afc365 | ||
|
|
ef0614ad45 | ||
|
|
04f4683399 | ||
|
|
f55f27b0d9 | ||
|
|
eb91ecf1fb | ||
|
|
2b0b927b0b | ||
|
|
86cab46b8d | ||
|
|
9ac9252f75 | ||
|
|
011ed3fbfd | ||
|
|
83dc5b9906 | ||
|
|
9ee4a7a7b8 | ||
|
|
3871c6a33e | ||
|
|
8707e4d9a3 | ||
|
|
df01fa7a9c | ||
|
|
b777a22d35 | ||
|
|
874e3b5e06 | ||
|
|
4d44755945 | ||
|
|
1a12fb3099 | ||
|
|
59208bdb85 | ||
|
|
9c8ade7ddd | ||
|
|
6005437001 | ||
|
|
60d931af9f | ||
|
|
7a96f5682e | ||
|
|
3dc28c2d17 | ||
|
|
2e12bb5f5c | ||
|
|
cd70acde66 | ||
|
|
efcf7eab0c | ||
|
|
86e51dad8a | ||
|
|
5f355c7f55 | ||
|
|
69a63855cc | ||
|
|
9af18bc100 | ||
|
|
0cd3df9d26 | ||
|
|
e027b0e9a0 | ||
|
|
78362341ff | ||
|
|
1a7d8cb99d | ||
|
|
395d54bf86 |
2
.github/workflows/mad_modelDiff.yml
vendored
2
.github/workflows/mad_modelDiff.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
||||
DATABASE=$2
|
||||
cd codeql-$QL_VARIANT
|
||||
SHORTNAME=`basename $DATABASE`
|
||||
python java/ql/src/utils/modelgenerator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE $SHORTNAME/$QL_VARIANT
|
||||
python misc/scripts/models-as-data/generate_mad.py --language java --with-summaries --with-sinks $DATABASE $SHORTNAME/$QL_VARIANT
|
||||
mkdir -p $MODELS/$SHORTNAME
|
||||
mv java/ql/lib/ext/generated/$SHORTNAME/$QL_VARIANT $MODELS/$SHORTNAME
|
||||
cd ..
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
# Experimental CodeQL cryptography
|
||||
**/experimental/quantum/ @github/ps-codeql
|
||||
/shared/quantum/ @github/ps-codeql
|
||||
|
||||
# CodeQL tools and associated docs
|
||||
/docs/codeql/codeql-cli/ @github/codeql-cli-reviewers
|
||||
|
||||
17
MODULE.bazel
17
MODULE.bazel
@@ -24,7 +24,7 @@ bazel_dep(name = "bazel_skylib", version = "1.7.1")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.0.0-codeql.1")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.1.3-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.40.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.17.4")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
@@ -193,10 +193,6 @@ use_repo(
|
||||
kotlin_extractor_deps,
|
||||
"codeql_kotlin_defaults",
|
||||
"codeql_kotlin_embeddable",
|
||||
"kotlin-compiler-1.5.0",
|
||||
"kotlin-compiler-1.5.10",
|
||||
"kotlin-compiler-1.5.20",
|
||||
"kotlin-compiler-1.5.30",
|
||||
"kotlin-compiler-1.6.0",
|
||||
"kotlin-compiler-1.6.20",
|
||||
"kotlin-compiler-1.7.0",
|
||||
@@ -208,10 +204,7 @@ use_repo(
|
||||
"kotlin-compiler-2.0.20-Beta2",
|
||||
"kotlin-compiler-2.1.0-Beta1",
|
||||
"kotlin-compiler-2.1.20-Beta1",
|
||||
"kotlin-compiler-embeddable-1.5.0",
|
||||
"kotlin-compiler-embeddable-1.5.10",
|
||||
"kotlin-compiler-embeddable-1.5.20",
|
||||
"kotlin-compiler-embeddable-1.5.30",
|
||||
"kotlin-compiler-2.2.0-Beta1",
|
||||
"kotlin-compiler-embeddable-1.6.0",
|
||||
"kotlin-compiler-embeddable-1.6.20",
|
||||
"kotlin-compiler-embeddable-1.7.0",
|
||||
@@ -223,10 +216,7 @@ use_repo(
|
||||
"kotlin-compiler-embeddable-2.0.20-Beta2",
|
||||
"kotlin-compiler-embeddable-2.1.0-Beta1",
|
||||
"kotlin-compiler-embeddable-2.1.20-Beta1",
|
||||
"kotlin-stdlib-1.5.0",
|
||||
"kotlin-stdlib-1.5.10",
|
||||
"kotlin-stdlib-1.5.20",
|
||||
"kotlin-stdlib-1.5.30",
|
||||
"kotlin-compiler-embeddable-2.2.0-Beta1",
|
||||
"kotlin-stdlib-1.6.0",
|
||||
"kotlin-stdlib-1.6.20",
|
||||
"kotlin-stdlib-1.7.0",
|
||||
@@ -238,6 +228,7 @@ use_repo(
|
||||
"kotlin-stdlib-2.0.20-Beta2",
|
||||
"kotlin-stdlib-2.1.0-Beta1",
|
||||
"kotlin-stdlib-2.1.20-Beta1",
|
||||
"kotlin-stdlib-2.2.0-Beta1",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.4.9
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.8
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
actions/ql/lib/change-notes/released/0.4.9.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.9.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.9
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.8
|
||||
lastReleaseVersion: 0.4.9
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.9-dev
|
||||
version: 0.4.10-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.6.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
3
actions/ql/src/change-notes/released/0.6.1.md
Normal file
3
actions/ql/src/change-notes/released/0.6.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.0
|
||||
lastReleaseVersion: 0.6.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.1-dev
|
||||
version: 0.6.2-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -299,6 +299,7 @@ ql/cpp/ql/src/experimental/cryptography/inventory/new_models/SigningAlgorithms.q
|
||||
ql/cpp/ql/src/experimental/cryptography/inventory/new_models/SymmetricEncryptionAlgorithms.ql
|
||||
ql/cpp/ql/src/experimental/cryptography/inventory/new_models/SymmetricPaddingAlgorithms.ql
|
||||
ql/cpp/ql/src/experimental/cryptography/inventory/new_models/UnknownAsymmetricKeyGeneration.ql
|
||||
ql/cpp/ql/src/experimental/quantum/PrintCBOMGraph.ql
|
||||
ql/cpp/ql/src/external/examples/filters/BumpMetricBy10.ql
|
||||
ql/cpp/ql/src/external/examples/filters/EditDefectMessage.ql
|
||||
ql/cpp/ql/src/external/examples/filters/ExcludeGeneratedCode.ql
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 4.3.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed an infinite loop in `semmle.code.cpp.rangeanalysis.new.RangeAnalysis` when computing ranges in very large and complex function bodies.
|
||||
|
||||
## 4.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
5
cpp/ql/lib/change-notes/released/4.3.1.md
Normal file
5
cpp/ql/lib/change-notes/released/4.3.1.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 4.3.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed an infinite loop in `semmle.code.cpp.rangeanalysis.new.RangeAnalysis` when computing ranges in very large and complex function bodies.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 4.3.0
|
||||
lastReleaseVersion: 4.3.1
|
||||
|
||||
113
cpp/ql/lib/experimental/quantum/Language.qll
Normal file
113
cpp/ql/lib/experimental/quantum/Language.qll
Normal file
@@ -0,0 +1,113 @@
|
||||
private import cpp as Language
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import codeql.quantum.experimental.Model
|
||||
|
||||
module CryptoInput implements InputSig<Language::Location> {
|
||||
class DataFlowNode = DataFlow::Node;
|
||||
|
||||
class LocatableElement = Language::Locatable;
|
||||
|
||||
class UnknownLocation = Language::UnknownDefaultLocation;
|
||||
|
||||
LocatableElement dfn_to_element(DataFlow::Node node) {
|
||||
result = node.asExpr() or
|
||||
result = node.asParameter() or
|
||||
result = node.asVariable()
|
||||
}
|
||||
|
||||
string locationToFileBaseNameAndLineNumberString(Location location) {
|
||||
result = location.getFile().getBaseName() + ":" + location.getStartLine()
|
||||
}
|
||||
|
||||
predicate artifactOutputFlowsToGenericInput(
|
||||
DataFlow::Node artifactOutput, DataFlow::Node otherInput
|
||||
) {
|
||||
ArtifactFlow::flow(artifactOutput, otherInput)
|
||||
}
|
||||
}
|
||||
|
||||
module Crypto = CryptographyBase<Language::Location, CryptoInput>;
|
||||
|
||||
module ArtifactFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::ArtifactInstance artifact).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(Crypto::FlowAwareElement other).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
}
|
||||
}
|
||||
|
||||
module ArtifactFlow = DataFlow::Global<ArtifactFlowConfig>;
|
||||
|
||||
/**
|
||||
* Artifact output to node input configuration
|
||||
*/
|
||||
abstract class AdditionalFlowInputStep extends DataFlow::Node {
|
||||
abstract DataFlow::Node getOutput();
|
||||
|
||||
final DataFlow::Node getInput() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic data source to node input configuration
|
||||
*/
|
||||
module GenericDataSourceFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::GenericSourceInstance i).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(Crypto::FlowAwareElement other).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
}
|
||||
}
|
||||
|
||||
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::ArtifactInstance artifact).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(Crypto::FlowAwareElement other).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
}
|
||||
}
|
||||
|
||||
module ArtifactUniversalFlow = DataFlow::Global<ArtifactUniversalFlowConfig>;
|
||||
|
||||
import OpenSSL.OpenSSL
|
||||
@@ -0,0 +1,170 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
/**
|
||||
* Traces 'known algorithms' to AVCs, specifically
|
||||
* algorithms that are in the set of known algorithm constants.
|
||||
* Padding-specific consumers exist that have their own values that
|
||||
* overlap with the known algorithm constants.
|
||||
* Padding consumers (specific padding consumers) are excluded from the set of sinks.
|
||||
*/
|
||||
module KnownOpenSSLAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof KnownOpenSSLAlgorithmConstant
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(OpenSSLAlgorithmValueConsumer c |
|
||||
c.getInputNode() = sink and
|
||||
not c instanceof PaddingAlgorithmValueConsumer
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
// False positive reducer, don't flow out through argv
|
||||
exists(VariableAccess va, Variable v |
|
||||
v.getAnAccess() = va and va = node.asExpr()
|
||||
or
|
||||
va = node.asIndirectExpr()
|
||||
|
|
||||
v.getName().matches("%argv")
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
knownPassThroughStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
module KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow =
|
||||
DataFlow::Global<KnownOpenSSLAlgorithmToAlgorithmValueConsumerConfig>;
|
||||
|
||||
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof KnownOpenSSLAlgorithmConstant
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(PaddingAlgorithmValueConsumer c | c.getInputNode() = sink)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
knownPassThroughStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
|
||||
DataFlow::Global<RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
|
||||
|
||||
class OpenSSLAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep {
|
||||
OpenSSLAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) }
|
||||
|
||||
override DataFlow::Node getOutput() {
|
||||
exists(AlgorithmPassthroughCall c | c.getInNode() = this and c.getOutNode() = result)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AlgorithmPassthroughCall extends Call {
|
||||
abstract DataFlow::Node getInNode();
|
||||
|
||||
abstract DataFlow::Node getOutNode();
|
||||
}
|
||||
|
||||
class CopyAndDupAlgorithmPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
CopyAndDupAlgorithmPassthroughCall() {
|
||||
// Flow out through any return or other argument of the same type
|
||||
// Assume flow in and out is asIndirectExpr or asDefinitingArgument since a pointer is assumed
|
||||
// to be involved
|
||||
// NOTE: not attempting to detect openssl specific copy/dup functions, but anything suspected to be copy/dup
|
||||
this.getTarget().getName().toLowerCase().matches(["%_dup%", "%_copy%"]) and
|
||||
exists(Expr inArg, Type t |
|
||||
inArg = this.getAnArgument() and t = inArg.getUnspecifiedType().stripType()
|
||||
|
|
||||
inNode.asIndirectExpr() = inArg and
|
||||
(
|
||||
// Case 1: flow through another argument as an out arg of the same type
|
||||
exists(Expr outArg |
|
||||
outArg = this.getAnArgument() and
|
||||
outArg != inArg and
|
||||
outArg.getUnspecifiedType().stripType() = t
|
||||
|
|
||||
outNode.asDefiningArgument() = outArg
|
||||
)
|
||||
or
|
||||
// Case 2: flow through the return value if the result is the same as the intput type
|
||||
exists(Expr outArg | outArg = this and outArg.getUnspecifiedType().stripType() = t |
|
||||
outNode.asIndirectExpr() = outArg
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInNode() { result = inNode }
|
||||
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class NIDToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
NIDToPointerPassthroughCall() {
|
||||
this.getTarget().getName() in ["OBJ_nid2obj", "OBJ_nid2ln", "OBJ_nid2sn"] and
|
||||
inNode.asExpr() = this.getArgument(0) and
|
||||
outNode.asExpr() = this
|
||||
//outNode.asIndirectExpr() = this
|
||||
}
|
||||
|
||||
override DataFlow::Node getInNode() { result = inNode }
|
||||
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class PointerToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
PointerToPointerPassthroughCall() {
|
||||
this.getTarget().getName() = "OBJ_txt2obj" and
|
||||
inNode.asIndirectExpr() = this.getArgument(0) and
|
||||
outNode.asIndirectExpr() = this
|
||||
or
|
||||
//outNode.asExpr() = this
|
||||
this.getTarget().getName() in ["OBJ_obj2txt", "i2t_ASN1_OBJECT"] and
|
||||
inNode.asIndirectExpr() = this.getArgument(2) and
|
||||
outNode.asDefiningArgument() = this.getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInNode() { result = inNode }
|
||||
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class PointerToNIDPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
PointerToNIDPassthroughCall() {
|
||||
this.getTarget().getName() in ["OBJ_obj2nid", "OBJ_ln2nid", "OBJ_sn2nid", "OBJ_txt2nid"] and
|
||||
(
|
||||
inNode.asIndirectExpr() = this.getArgument(0)
|
||||
or
|
||||
inNode.asExpr() = this.getArgument(0)
|
||||
) and
|
||||
outNode.asExpr() = this
|
||||
}
|
||||
|
||||
override DataFlow::Node getInNode() { result = inNode }
|
||||
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
// TODO: pkeys pass through EVP_PKEY_CTX_new and any similar variant
|
||||
predicate knownPassThroughStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(AlgorithmPassthroughCall c | c.getInNode() = node1 and c.getOutNode() = node2)
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import OpenSSLAlgorithmInstanceBase
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
import AlgToAVCFlow
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSSLBlockModeAlgorithmConstant`, converts this to a block family type.
|
||||
* Does not bind if there is know mapping (no mapping to 'unknown' or 'other').
|
||||
*/
|
||||
predicate knownOpenSSLConstantToBlockModeFamilyType(
|
||||
KnownOpenSSLBlockModeAlgorithmConstant e, Crypto::TBlockCipherModeOfOperationType type
|
||||
) {
|
||||
exists(string name |
|
||||
name = e.getNormalizedName() and
|
||||
(
|
||||
name.matches("CBC") and type instanceof Crypto::CBC
|
||||
or
|
||||
name.matches("CFB%") and type instanceof Crypto::CFB
|
||||
or
|
||||
name.matches("CTR") and type instanceof Crypto::CTR
|
||||
or
|
||||
name.matches("GCM") and type instanceof Crypto::GCM
|
||||
or
|
||||
name.matches("OFB") and type instanceof Crypto::OFB
|
||||
or
|
||||
name.matches("XTS") and type instanceof Crypto::XTS
|
||||
or
|
||||
name.matches("CCM") and type instanceof Crypto::CCM
|
||||
or
|
||||
name.matches("GCM") and type instanceof Crypto::GCM
|
||||
or
|
||||
name.matches("CCM") and type instanceof Crypto::CCM
|
||||
or
|
||||
name.matches("ECB") and type instanceof Crypto::ECB
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLBlockModeConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::ModeOfOperationAlgorithmInstance instanceof KnownOpenSSLBlockModeAlgorithmConstant
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
|
||||
KnownOpenSSLBlockModeConstantAlgorithmInstance() {
|
||||
// Two possibilities:
|
||||
// 1) The source is a literal and flows to a getter, then we know we have an instance
|
||||
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectAlgorithmValueConsumer and getterCall = this
|
||||
}
|
||||
|
||||
override Crypto::TBlockCipherModeOfOperationType getModeType() {
|
||||
knownOpenSSLConstantToBlockModeFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSSLConstantToBlockModeFamilyType(this, _) and result = Crypto::OtherMode()
|
||||
}
|
||||
|
||||
// NOTE: I'm not going to attempt to parse out the mode specific part, so returning
|
||||
// the same as the raw name for now.
|
||||
override string getRawModeAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import KnownAlgorithmConstants
|
||||
import Crypto::KeyOpAlg as KeyOpAlg
|
||||
import OpenSSLAlgorithmInstanceBase
|
||||
import PaddingAlgorithmInstance
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import AlgToAVCFlow
|
||||
import BlockAlgorithmInstance
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSSLCipherAlgorithmConstant`, converts this to a cipher family type.
|
||||
* Does not bind if there is know mapping (no mapping to 'unknown' or 'other').
|
||||
*/
|
||||
predicate knownOpenSSLConstantToCipherFamilyType(
|
||||
KnownOpenSSLCipherAlgorithmConstant e, Crypto::KeyOpAlg::TAlgorithm type
|
||||
) {
|
||||
exists(string name |
|
||||
name = e.getNormalizedName() and
|
||||
(
|
||||
name.matches("AES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::AES())
|
||||
or
|
||||
name.matches("ARIA%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::ARIA())
|
||||
or
|
||||
name.matches("BLOWFISH%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::BLOWFISH())
|
||||
or
|
||||
name.matches("BF%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::BLOWFISH())
|
||||
or
|
||||
name.matches("CAMELLIA%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::CAMELLIA())
|
||||
or
|
||||
name.matches("CHACHA20%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::CHACHA20())
|
||||
or
|
||||
name.matches("CAST5%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::CAST5())
|
||||
or
|
||||
name.matches("2DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DoubleDES())
|
||||
or
|
||||
name.matches("3DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TripleDES())
|
||||
or
|
||||
name.matches("DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DES())
|
||||
or
|
||||
name.matches("DESX%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DESX())
|
||||
or
|
||||
name.matches("GOST%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::GOST())
|
||||
or
|
||||
name.matches("IDEA%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::IDEA())
|
||||
or
|
||||
name.matches("KUZNYECHIK%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::KUZNYECHIK())
|
||||
or
|
||||
name.matches("MAGMA%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::MAGMA())
|
||||
or
|
||||
name.matches("RC2%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::RC2())
|
||||
or
|
||||
name.matches("RC4%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::RC4())
|
||||
or
|
||||
name.matches("RC5%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::RC5())
|
||||
or
|
||||
name.matches("RSA%") and type = KeyOpAlg::TAsymmetricCipher(KeyOpAlg::RSA())
|
||||
or
|
||||
name.matches("SEED%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::SEED())
|
||||
or
|
||||
name.matches("SM4%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::SM4())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLCipherConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::KeyOperationAlgorithmInstance instanceof KnownOpenSSLCipherAlgorithmConstant
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
|
||||
KnownOpenSSLCipherConstantAlgorithmInstance() {
|
||||
// Two possibilities:
|
||||
// 1) The source is a literal and flows to a getter, then we know we have an instance
|
||||
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectAlgorithmValueConsumer and getterCall = this
|
||||
}
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
|
||||
// if there is a block mode associated with the same element, then that's the block mode
|
||||
// note, if none are associated, we may need to parse if the cipher is a block cipher
|
||||
// to determine if this is an unknown vs not relevant.
|
||||
result = this
|
||||
}
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() {
|
||||
//TODO: the padding is either self, or it flows through getter ctx to a set padding call
|
||||
// like EVP_PKEY_CTX_set_rsa_padding
|
||||
result = this
|
||||
// TODO or trace through getter ctx to set padding
|
||||
}
|
||||
|
||||
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
override string getKeySizeFixed() {
|
||||
exists(int keySize |
|
||||
this.(KnownOpenSSLCipherAlgorithmConstant).getExplicitKeySize() = keySize and
|
||||
result = keySize.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override Crypto::KeyOpAlg::Algorithm getAlgorithmType() {
|
||||
knownOpenSSLConstantToCipherFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSSLConstantToCipherFamilyType(this, _) and
|
||||
result = Crypto::KeyOpAlg::TUnknownKeyOperationAlgorithmType()
|
||||
}
|
||||
|
||||
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
|
||||
// TODO: trace to any key size initializer, symmetric and asymmetric
|
||||
none()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import AlgToAVCFlow
|
||||
|
||||
predicate knownOpenSSLConstantToHashFamilyType(
|
||||
KnownOpenSSLHashAlgorithmConstant e, Crypto::THashType type
|
||||
) {
|
||||
exists(string name |
|
||||
name = e.getNormalizedName() and
|
||||
(
|
||||
name.matches("BLAKE2B") and type instanceof Crypto::BLAKE2B
|
||||
or
|
||||
name.matches("BLAKE2S") and type instanceof Crypto::BLAKE2S
|
||||
or
|
||||
name.matches("GOST%") and type instanceof Crypto::GOSTHash
|
||||
or
|
||||
name.matches("MD2") and type instanceof Crypto::MD2
|
||||
or
|
||||
name.matches("MD4") and type instanceof Crypto::MD4
|
||||
or
|
||||
name.matches("MD5") and type instanceof Crypto::MD5
|
||||
or
|
||||
name.matches("MDC2") and type instanceof Crypto::MDC2
|
||||
or
|
||||
name.matches("POLY1305") and type instanceof Crypto::POLY1305
|
||||
or
|
||||
name.matches(["SHA", "SHA1"]) and type instanceof Crypto::SHA1
|
||||
or
|
||||
name.matches("SHA+%") and not name.matches(["SHA1", "SHA3-"]) and type instanceof Crypto::SHA2
|
||||
or
|
||||
name.matches("SHA3-%") and type instanceof Crypto::SHA3
|
||||
or
|
||||
name.matches(["SHAKE"]) and type instanceof Crypto::SHAKE
|
||||
or
|
||||
name.matches("SM3") and type instanceof Crypto::SM3
|
||||
or
|
||||
name.matches("RIPEMD160") and type instanceof Crypto::RIPEMD160
|
||||
or
|
||||
name.matches("WHIRLPOOL") and type instanceof Crypto::WHIRLPOOL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLHashConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::HashAlgorithmInstance instanceof KnownOpenSSLHashAlgorithmConstant
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
|
||||
KnownOpenSSLHashConstantAlgorithmInstance() {
|
||||
// Two possibilities:
|
||||
// 1) The source is a literal and flows to a getter, then we know we have an instance
|
||||
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectAlgorithmValueConsumer and getterCall = this
|
||||
}
|
||||
|
||||
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }
|
||||
|
||||
override Crypto::THashType getHashFamily() {
|
||||
knownOpenSSLConstantToHashFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSSLConstantToHashFamilyType(this, _) and result = Crypto::OtherHashType()
|
||||
}
|
||||
|
||||
override string getRawHashAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
override int getFixedDigestLength() {
|
||||
this.(KnownOpenSSLHashAlgorithmConstant).getExplicitDigestLength() = result
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
abstract class OpenSSLAlgorithmInstance extends Crypto::AlgorithmInstance {
|
||||
abstract OpenSSLAlgorithmValueConsumer getAVC();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import OpenSSLAlgorithmInstanceBase
|
||||
import CipherAlgorithmInstance
|
||||
import PaddingAlgorithmInstance
|
||||
import BlockAlgorithmInstance
|
||||
import HashAlgorithmInstance
|
||||
@@ -0,0 +1,167 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import OpenSSLAlgorithmInstanceBase
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import AlgToAVCFlow
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSSLPaddingAlgorithmConstant`, converts this to a padding family type.
|
||||
* Does not bind if there is know mapping (no mapping to 'unknown' or 'other').
|
||||
*/
|
||||
predicate knownOpenSSLConstantToPaddingFamilyType(
|
||||
KnownOpenSSLPaddingAlgorithmConstant e, Crypto::TPaddingType type
|
||||
) {
|
||||
exists(string name |
|
||||
name = e.getNormalizedName() and
|
||||
(
|
||||
name.matches("OAEP") and type = Crypto::OAEP()
|
||||
or
|
||||
name.matches("PSS") and type = Crypto::PSS()
|
||||
or
|
||||
name.matches("PKCS7") and type = Crypto::PKCS7()
|
||||
or
|
||||
name.matches("PKCS1V15") and type = Crypto::PKCS1_v1_5()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
//abstract class OpenSSLPaddingAlgorithmInstance extends OpenSSLAlgorithmInstance, Crypto::PaddingAlgorithmInstance{}
|
||||
// TODO: need to alter this to include known padding constants which don't have the
|
||||
// same mechanics as those with known nids
|
||||
class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::PaddingAlgorithmInstance instanceof Expr
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
boolean isPaddingSpecificConsumer;
|
||||
|
||||
KnownOpenSSLPaddingConstantAlgorithmInstance() {
|
||||
// three possibilities:
|
||||
// 1) The source is a 'typical' literal and flows to a getter, then we know we have an instance
|
||||
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that
|
||||
// 3) the source is a padding-specific literal flowing to a padding-specific consumer
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
this instanceof KnownOpenSSLPaddingAlgorithmConstant and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) and
|
||||
isPaddingSpecificConsumer = false
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectAlgorithmValueConsumer and
|
||||
getterCall = this and
|
||||
this instanceof KnownOpenSSLPaddingAlgorithmConstant and
|
||||
isPaddingSpecificConsumer = false
|
||||
or
|
||||
// Possibility 3:
|
||||
// from rsa.h in openssl:
|
||||
// # define RSA_PKCS1_PADDING 1
|
||||
// # define RSA_NO_PADDING 3
|
||||
// # define RSA_PKCS1_OAEP_PADDING 4
|
||||
// # define RSA_X931_PADDING 5
|
||||
// /* EVP_PKEY_ only */
|
||||
// # define RSA_PKCS1_PSS_PADDING 6
|
||||
// # define RSA_PKCS1_WITH_TLS_PADDING 7
|
||||
// /* internal RSA_ only */
|
||||
// # define RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING 8
|
||||
this instanceof Literal and
|
||||
this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8] and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a padding-specific consumer
|
||||
RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
) and
|
||||
isPaddingSpecificConsumer = true
|
||||
}
|
||||
|
||||
override string getRawPaddingAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }
|
||||
|
||||
override Crypto::TPaddingType getPaddingType() {
|
||||
isPaddingSpecificConsumer = true and
|
||||
(
|
||||
if this.(Literal).getValue().toInt() in [1, 7, 8]
|
||||
then result = Crypto::PKCS1_v1_5()
|
||||
else
|
||||
if this.(Literal).getValue().toInt() = 3
|
||||
then result = Crypto::NoPadding()
|
||||
else
|
||||
if this.(Literal).getValue().toInt() = 4
|
||||
then result = Crypto::OAEP()
|
||||
else
|
||||
if this.(Literal).getValue().toInt() = 5
|
||||
then result = Crypto::ANSI_X9_23()
|
||||
else
|
||||
if this.(Literal).getValue().toInt() = 6
|
||||
then result = Crypto::PSS()
|
||||
else result = Crypto::OtherPadding()
|
||||
)
|
||||
or
|
||||
isPaddingSpecificConsumer = false and
|
||||
knownOpenSSLConstantToPaddingFamilyType(this, result)
|
||||
}
|
||||
}
|
||||
|
||||
// // Values used for EVP_PKEY_CTX_set_rsa_padding, these are
|
||||
// // not the same as 'typical' constants found in the set of known algorithm constants
|
||||
// // they do not have an NID
|
||||
// // TODO: what about setting the padding directly?
|
||||
// class KnownRSAPaddingConstant extends OpenSSLPaddingAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof Literal
|
||||
// {
|
||||
// KnownRSAPaddingConstant() {
|
||||
// // from rsa.h in openssl:
|
||||
// // # define RSA_PKCS1_PADDING 1
|
||||
// // # define RSA_NO_PADDING 3
|
||||
// // # define RSA_PKCS1_OAEP_PADDING 4
|
||||
// // # define RSA_X931_PADDING 5
|
||||
// // /* EVP_PKEY_ only */
|
||||
// // # define RSA_PKCS1_PSS_PADDING 6
|
||||
// // # define RSA_PKCS1_WITH_TLS_PADDING 7
|
||||
// // /* internal RSA_ only */
|
||||
// // # define RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING 8
|
||||
// this instanceof Literal and
|
||||
// this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8]
|
||||
// // TODO: trace to padding-specific consumers
|
||||
// RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
|
||||
// }
|
||||
// override string getRawPaddingAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
// override Crypto::TPaddingType getPaddingType() {
|
||||
// if this.(Literal).getValue().toInt() in [1, 6, 7, 8]
|
||||
// then result = Crypto::PKCS1_v1_5()
|
||||
// else
|
||||
// if this.(Literal).getValue().toInt() = 3
|
||||
// then result = Crypto::NoPadding()
|
||||
// else
|
||||
// if this.(Literal).getValue().toInt() = 4
|
||||
// then result = Crypto::OAEP()
|
||||
// else
|
||||
// if this.(Literal).getValue().toInt() = 5
|
||||
// then result = Crypto::ANSI_X9_23()
|
||||
// else result = Crypto::OtherPadding()
|
||||
// }
|
||||
// }
|
||||
class OAEPPaddingAlgorithmInstance extends Crypto::OAEPPaddingAlgorithmInstance,
|
||||
KnownOpenSSLPaddingConstantAlgorithmInstance
|
||||
{
|
||||
OAEPPaddingAlgorithmInstance() {
|
||||
this.(Crypto::PaddingAlgorithmInstance).getPaddingType() = Crypto::OAEP()
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getOAEPEncodingHashAlgorithm() {
|
||||
none() //TODO
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getMGF1HashAlgorithm() {
|
||||
none() //TODO
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.LibraryDetector
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
import OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
abstract class CipherAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { }
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_fetch.html
|
||||
class EVPCipherAlgorithmValueConsumer extends CipherAlgorithmValueConsumer {
|
||||
DataFlow::Node valueArgNode;
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EVPCipherAlgorithmValueConsumer() {
|
||||
resultNode.asExpr() = this and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget()) and
|
||||
(
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_get_cipherbyname", "EVP_get_cipherbyobj", "EVP_get_cipherbynid"
|
||||
] and
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() in ["EVP_CIPHER_fetch", "EVP_ASYM_CIPHER_fetch"] and
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getResultNode() { result = resultNode }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
|
||||
|
||||
// override DataFlow::Node getInputNode() { result = valueArgNode }
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
|
||||
//TODO: As a potential alternative, for OpenSSL only, add a generic source node for literals and only create flow (flowsTo) to
|
||||
// OpenSSL AVCs... the unknown literal sources would have to be any literals not in the known set.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
// TODO: can self referential to itself, which is also an algorithm (Known algorithm)
|
||||
/**
|
||||
* Cases like EVP_MD5(),
|
||||
* there is no input, rather it directly gets an algorithm
|
||||
* and returns it.
|
||||
*/
|
||||
class DirectAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
Expr resultExpr;
|
||||
|
||||
DirectAlgorithmValueConsumer() {
|
||||
this instanceof KnownOpenSSLAlgorithmConstant and
|
||||
this instanceof Call and
|
||||
resultExpr = this and
|
||||
resultNode.asExpr() = resultExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* These cases take in no explicit value (the value is implicit)
|
||||
*/
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() { none() }
|
||||
|
||||
override DataFlow::Node getResultNode() { result = resultNode }
|
||||
|
||||
// override DataFlow::Node getOutputNode() { result = resultNode }
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
// Note: algorithm source definitions enforces that
|
||||
// this class will be a known algorithm source
|
||||
result = this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// import EVPHashInitializer
|
||||
// import EVPHashOperation
|
||||
// import EVPHashAlgorithmSource
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
import experimental.quantum.OpenSSL.LibraryDetector
|
||||
|
||||
abstract class HashAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { }
|
||||
|
||||
/**
|
||||
* EVP_Q_Digest directly consumes algorithm constant values
|
||||
*/
|
||||
class EVP_Q_Digest_Algorithm_Consumer extends OpenSSLAlgorithmValueConsumer {
|
||||
EVP_Q_Digest_Algorithm_Consumer() {
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget()) and
|
||||
this.(Call).getTarget().getName() = "EVP_Q_digest"
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() {
|
||||
result.asExpr() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
|
||||
}
|
||||
|
||||
override DataFlow::Node getResultNode() {
|
||||
// EVP_Q_Digest directly consumes the algorithm constant value and performs the operation, there is no
|
||||
// algorithm result
|
||||
none()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import experimental.quantum.Language
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
abstract class OpenSSLAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer instanceof Call {
|
||||
/**
|
||||
* Returns the node representing the resulting algorithm
|
||||
*/
|
||||
abstract DataFlow::Node getResultNode();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import OpenSSLAlgorithmValueConsumerBase
|
||||
import CipherAlgorithmValueConsumer
|
||||
import DirectAlgorithmValueConsumer
|
||||
import PaddingAlgorithmValueConsumer
|
||||
import HashAlgorithmValueConsumer
|
||||
@@ -0,0 +1,36 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.LibraryDetector
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
import OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
abstract class PaddingAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { }
|
||||
|
||||
// https://docs.openssl.org/master/man7/EVP_ASYM_CIPHER-RSA/#rsa-asymmetric-cipher-parameters
|
||||
// TODO: need to handle setting padding through EVP_PKEY_CTX_set_params, where modes like "OSSL_PKEY_RSA_PAD_MODE_OAEP"
|
||||
// are set.
|
||||
class EVP_PKEY_CTX_set_rsa_padding_AlgorithmValueConsumer extends PaddingAlgorithmValueConsumer {
|
||||
DataFlow::Node valueArgNode;
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EVP_PKEY_CTX_set_rsa_padding_AlgorithmValueConsumer() {
|
||||
resultNode.asExpr() = this and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget()) and
|
||||
(
|
||||
this.(Call).getTarget().getName() in ["EVP_PKEY_CTX_set_rsa_padding"] and
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getResultNode() { result = resultNode }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
|
||||
|
||||
// override DataFlow::Node getInputNode() { result = valueArgNode }
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
|
||||
//TODO: As a potential alternative, for OpenSSL only, add a generic source node for literals and only create flow (flowsTo) to
|
||||
// OpenSSL AVCs... the unknown literal sources would have to be any literals not in the known set.
|
||||
}
|
||||
}
|
||||
99
cpp/ql/lib/experimental/quantum/OpenSSL/CtxFlow.qll
Normal file
99
cpp/ql/lib/experimental/quantum/OpenSSL/CtxFlow.qll
Normal file
@@ -0,0 +1,99 @@
|
||||
//TODO: model as data on open APIs should be able to get common flows, and obviate some of this
|
||||
// e.g., copy/dup calls, need to ingest those models for openSSL and refactor.
|
||||
/**
|
||||
* In OpenSSL, flow between 'context' parameters is often used to
|
||||
* store state/config of how an operation will eventually be performed.
|
||||
* Tracing algorithms and configurations to operations therefore
|
||||
* requires tracing context parameters for many OpenSSL apis.
|
||||
*
|
||||
* This library provides a dataflow analysis to track context parameters
|
||||
* between any two functions accepting openssl context parameters.
|
||||
* The dataflow takes into consideration flowing through duplication and copy calls
|
||||
* as well as flow through flow killers (free/reset calls).
|
||||
*
|
||||
* TODO: we may need to revisit 'free' as a dataflow killer, depending on how
|
||||
* we want to model use after frees.
|
||||
*
|
||||
* This library also provides classes to represent context Types and relevant
|
||||
* arguments/expressions.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
class CTXType extends Type {
|
||||
CTXType() {
|
||||
// TODO: should we limit this to an openssl path?
|
||||
this.getUnspecifiedType().stripType().getName().matches("evp_%ctx_%st")
|
||||
}
|
||||
}
|
||||
|
||||
class CTXPointerExpr extends Expr {
|
||||
CTXPointerExpr() {
|
||||
this.getType() instanceof CTXType and
|
||||
this.getType() instanceof PointerType
|
||||
}
|
||||
}
|
||||
|
||||
class CTXPointerArgument extends CTXPointerExpr {
|
||||
CTXPointerArgument() { exists(Call c | c.getAnArgument() = this) }
|
||||
|
||||
Call getCall() { result.getAnArgument() = this }
|
||||
}
|
||||
|
||||
class CTXClearCall extends Call {
|
||||
CTXClearCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%free%", "%reset%"]) and
|
||||
this.getAnArgument() instanceof CTXPointerArgument
|
||||
}
|
||||
}
|
||||
|
||||
class CTXCopyOutArgCall extends Call {
|
||||
CTXCopyOutArgCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%copy%"]) and
|
||||
this.getAnArgument() instanceof CTXPointerArgument
|
||||
}
|
||||
}
|
||||
|
||||
class CTXCopyReturnCall extends Call {
|
||||
CTXCopyReturnCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%dup%"]) and
|
||||
this.getAnArgument() instanceof CTXPointerArgument and
|
||||
this instanceof CTXPointerExpr
|
||||
}
|
||||
}
|
||||
|
||||
module OpenSSLCTXArgumentFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CTXPointerArgument }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof CTXPointerArgument }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(CTXClearCall c | c.getAnArgument() = node.asExpr())
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(CTXCopyOutArgCall c |
|
||||
c.getAnArgument() = node1.asExpr() and
|
||||
c.getAnArgument() = node2.asExpr() and
|
||||
node1.asExpr() != node2.asExpr() and
|
||||
node2.asExpr().getType() instanceof CTXType
|
||||
)
|
||||
or
|
||||
exists(CTXCopyReturnCall c |
|
||||
c.getAnArgument() = node1.asExpr() and
|
||||
c = node2.asExpr() and
|
||||
node1.asExpr() != node2.asExpr() and
|
||||
node2.asExpr().getType() instanceof CTXType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module OpenSSLCTXArgumentFlow = DataFlow::Global<OpenSSLCTXArgumentFlowConfig>;
|
||||
|
||||
predicate ctxArgFlowsToCtxArg(CTXPointerArgument source, CTXPointerArgument sink) {
|
||||
exists(DataFlow::Node a, DataFlow::Node b |
|
||||
OpenSSLCTXArgumentFlow::flow(a, b) and
|
||||
a.asExpr() = source and
|
||||
b.asExpr() = sink
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import cpp
|
||||
|
||||
predicate isPossibleOpenSSLFunction(Function f) {
|
||||
isPossibleOpenSSLLocation(f.getADeclarationLocation())
|
||||
}
|
||||
|
||||
predicate isPossibleOpenSSLLocation(Location l) { l.toString().toLowerCase().matches("%openssl%") }
|
||||
9
cpp/ql/lib/experimental/quantum/OpenSSL/OpenSSL.qll
Normal file
9
cpp/ql/lib/experimental/quantum/OpenSSL/OpenSSL.qll
Normal file
@@ -0,0 +1,9 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
module OpenSSLModel {
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* see: https://docs.openssl.org/master/man3/EVP_EncryptInit/
|
||||
* Models cipher initialization for EVP cipher operations.
|
||||
*/
|
||||
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
|
||||
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EVP_Cipher_Initializer initCall | sink.asExpr() = initCall.getOperationSubtypeArg())
|
||||
}
|
||||
}
|
||||
|
||||
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
|
||||
|
||||
int getEncConfigValue(Expr e) {
|
||||
exists(EVP_Cipher_Initializer initCall | e = initCall.getOperationSubtypeArg()) and
|
||||
exists(DataFlow::Node a, DataFlow::Node b |
|
||||
EncValToInitEncArgFlow::flow(a, b) and b.asExpr() = e and result = a.asExpr().getValue().toInt()
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[i]
|
||||
Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
|
||||
if i = 0
|
||||
then result instanceof Crypto::TEncryptMode
|
||||
else
|
||||
if i = 1
|
||||
then result instanceof Crypto::TDecryptMode
|
||||
else result instanceof Crypto::TUnknownKeyOperationMode
|
||||
}
|
||||
|
||||
// TODO: need to add key consumer
|
||||
abstract class EVP_Cipher_Initializer extends Call {
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
abstract Expr getKeyArg();
|
||||
|
||||
abstract Expr getIVArg();
|
||||
|
||||
// abstract Crypto::CipherOperationSubtype getCipherOperationSubtype();
|
||||
abstract Expr getOperationSubtypeArg();
|
||||
|
||||
Crypto::KeyOperationSubtype getCipherOperationSubtype() {
|
||||
if this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
|
||||
then result instanceof Crypto::TEncryptMode
|
||||
else
|
||||
if this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
|
||||
then result instanceof Crypto::TDecryptMode
|
||||
else
|
||||
if exists(getEncConfigValue(this.getOperationSubtypeArg()))
|
||||
then result = intToCipherOperationSubtype(getEncConfigValue(this.getOperationSubtypeArg()))
|
||||
else result instanceof Crypto::TUnknownKeyOperationMode
|
||||
}
|
||||
}
|
||||
|
||||
abstract class EVP_EX_Initializer extends EVP_Cipher_Initializer {
|
||||
override Expr getKeyArg() { result = this.(Call).getArgument(3) }
|
||||
|
||||
override Expr getIVArg() { result = this.(Call).getArgument(4) }
|
||||
}
|
||||
|
||||
abstract class EVP_EX2_Initializer extends EVP_Cipher_Initializer {
|
||||
override Expr getKeyArg() { result = this.(Call).getArgument(2) }
|
||||
|
||||
override Expr getIVArg() { result = this.(Call).getArgument(3) }
|
||||
}
|
||||
|
||||
class EVP_Cipher_EX_Init_Call extends EVP_EX_Initializer {
|
||||
EVP_Cipher_EX_Init_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptInit_ex", "EVP_DecryptInit_ex", "EVP_CipherInit_ex"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getOperationSubtypeArg() {
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result = this.(Call).getArgument(5)
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_Cipher_EX2_or_Simple_Init_Call extends EVP_EX2_Initializer {
|
||||
EVP_Cipher_EX2_or_Simple_Init_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptInit_ex2", "EVP_DecryptInit_ex2", "EVP_CipherInit_ex2", "EVP_EncryptInit",
|
||||
"EVP_DecryptInit", "EVP_CipherInit"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getOperationSubtypeArg() {
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result = this.(Call).getArgument(4)
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
|
||||
EVP_CipherInit_SKEY_Call() { this.(Call).getTarget().getName() in ["EVP_CipherInit_SKEY"] }
|
||||
|
||||
override Expr getOperationSubtypeArg() { result = this.(Call).getArgument(5) }
|
||||
}
|
||||
|
||||
class EVPCipherInitializerAlgorithmArgument extends Expr {
|
||||
EVPCipherInitializerAlgorithmArgument() {
|
||||
exists(EVP_Cipher_Initializer initCall | this = initCall.getAlgorithmArg())
|
||||
}
|
||||
}
|
||||
|
||||
class EVPCipherInitializerKeyArgument extends Expr {
|
||||
EVPCipherInitializerKeyArgument() {
|
||||
exists(EVP_Cipher_Initializer initCall | this = initCall.getKeyArg())
|
||||
}
|
||||
}
|
||||
|
||||
class EVPCipherInitializerIVArgument extends Expr {
|
||||
EVPCipherInitializerIVArgument() {
|
||||
exists(EVP_Cipher_Initializer initCall | this = initCall.getIVArg())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
import EVPCipherInitializer
|
||||
import OpenSSLOperationBase
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EVP_Cipher_Operation c | c.getInitCall().getAlgorithmArg() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
private module AlgGetterToAlgConsumerFlow = DataFlow::Global<AlgGetterToAlgConsumerConfig>;
|
||||
|
||||
// import experimental.quantum.OpenSSL.AlgorithmValueConsumers.AlgorithmValueConsumers
|
||||
// import OpenSSLOperation
|
||||
// class EVPCipherOutput extends CipherOutputArtifact {
|
||||
// EVPCipherOutput() { exists(EVP_Cipher_Operation op | op.getOutputArg() = this) }
|
||||
// override DataFlow::Node getOutputNode() { result.asDefiningArgument() = this }
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* see: https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
|
||||
* Base configuration for all EVP cipher operations.
|
||||
* NOTE: cannot extend instance of OpenSSLOperation, as we need to override
|
||||
* elements of OpenSSLOperation (i.e., we are creating an instance)
|
||||
*/
|
||||
abstract class EVP_Cipher_Operation extends OpenSSLOperation, Crypto::KeyOperationInstance {
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
result instanceof Crypto::TEncryptMode and
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
|
||||
or
|
||||
result instanceof Crypto::TDecryptMode and
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
|
||||
or
|
||||
result = this.getInitCall().getCipherOperationSubtype() and
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipher%")
|
||||
}
|
||||
|
||||
EVP_Cipher_Initializer getInitCall() {
|
||||
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
||||
this.getInitCall().getIVArg() = result.asExpr()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
this.getInitCall().getKeyArg() = result.asExpr()
|
||||
}
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result = this.getOutputNode() }
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
DataFlow::exprNode(this.getInitCall().getAlgorithmArg()))
|
||||
}
|
||||
}
|
||||
|
||||
// abstract class EVP_Update_Call extends EVP_Cipher_Operation { }
|
||||
abstract class EVP_Final_Call extends EVP_Cipher_Operation {
|
||||
override Expr getInputArg() { none() }
|
||||
}
|
||||
|
||||
// TODO: only model Final (model final as operation and model update but not as an operation)
|
||||
// Updates are multiple input consumers (most important)
|
||||
// TODO: assuming update doesn't ouput, otherwise it outputs artifacts, but is not an operation
|
||||
class EVP_Cipher_Call extends EVP_Cipher_Operation {
|
||||
EVP_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(2) }
|
||||
}
|
||||
|
||||
// ******* TODO: model UPDATE but not as the core operation, rather a step towards final
|
||||
// see the JCA
|
||||
// class EVP_Encrypt_Decrypt_or_Cipher_Update_Call extends EVP_Update_Call {
|
||||
// EVP_Encrypt_Decrypt_or_Cipher_Update_Call() {
|
||||
// this.(Call).getTarget().getName() in [
|
||||
// "EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
|
||||
// ]
|
||||
// }
|
||||
// override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
// }
|
||||
class EVP_Encrypt_Decrypt_or_Cipher_Final_Call extends EVP_Final_Call {
|
||||
EVP_Encrypt_Decrypt_or_Cipher_Final_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptFinal_ex", "EVP_DecryptFinal_ex", "EVP_CipherFinal_ex", "EVP_EncryptFinal",
|
||||
"EVP_DecryptFinal", "EVP_CipherFinal"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_PKEY_Operation extends EVP_Cipher_Operation {
|
||||
EVP_PKEY_Operation() {
|
||||
this.(Call).getTarget().getName() in ["EVP_PKEY_decrypt", "EVP_PKEY_encrypt"]
|
||||
}
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
// TODO: how PKEY is initialized is different that symmetric cipher
|
||||
// Consider making an entirely new class for this and specializing
|
||||
// the get init call
|
||||
}
|
||||
|
||||
class EVPCipherInputArgument extends Expr {
|
||||
EVPCipherInputArgument() { exists(EVP_Cipher_Operation op | op.getInputArg() = this) }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import cpp
|
||||
|
||||
abstract class EVP_Hash_Initializer extends Call {
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
abstract Expr getAlgorithmArg();
|
||||
}
|
||||
|
||||
class EVP_DigestInit_Variant_Calls extends EVP_Hash_Initializer {
|
||||
EVP_DigestInit_Variant_Calls() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_DigestInit", "EVP_DigestInit_ex", "EVP_DigestInit_ex2"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
*/
|
||||
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
import experimental.quantum.OpenSSL.LibraryDetector
|
||||
import OpenSSLOperationBase
|
||||
import EVPHashInitializer
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
// import EVPHashConsumers
|
||||
abstract class EVP_Hash_Operation extends OpenSSLOperation, Crypto::HashOperationInstance {
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
EVP_Hash_Initializer getInitCall() {
|
||||
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
|
||||
}
|
||||
}
|
||||
|
||||
private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EVP_Hash_Operation c | c.getInitCall().getAlgorithmArg() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
private module AlgGetterToAlgConsumerFlow = DataFlow::Global<AlgGetterToAlgConsumerConfig>;
|
||||
|
||||
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
class EVP_Q_Digest_Operation extends EVP_Hash_Operation {
|
||||
EVP_Q_Digest_Operation() {
|
||||
this.(Call).getTarget().getName() = "EVP_Q_digest" and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
}
|
||||
|
||||
//override Crypto::AlgorithmConsumer getAlgorithmConsumer() { }
|
||||
override EVP_Hash_Initializer getInitCall() {
|
||||
// This variant of digest does not use an init
|
||||
// and even if it were used, the init would be ignored/undefined
|
||||
none()
|
||||
}
|
||||
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(5) }
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result = this.getOutputNode() }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
// The operation is a direct algorithm consumer
|
||||
// NOTE: the operation itself is already modeld as a value consumer, so we can
|
||||
// simply return 'this', see modeled hash algorithm consuers for EVP_Q_Digest
|
||||
this = result
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_Digest_Operation extends EVP_Hash_Operation {
|
||||
EVP_Digest_Operation() {
|
||||
this.(Call).getTarget().getName() = "EVP_Digest" and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
}
|
||||
|
||||
// There is no context argument for this function
|
||||
override Expr getContextArg() { none() }
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
DataFlow::exprNode(this.(Call).getArgument(4)))
|
||||
}
|
||||
|
||||
override EVP_Hash_Initializer getInitCall() {
|
||||
// This variant of digest does not use an init
|
||||
// and even if it were used, the init would be ignored/undefined
|
||||
none()
|
||||
}
|
||||
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(2) }
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result = this.getOutputNode() }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
|
||||
}
|
||||
// // override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
// // AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
// // DataFlow::exprNode(this.getInitCall().getAlgorithmArg()))
|
||||
// // }
|
||||
// // ***** TODO *** complete modelinlg for hash operations, but have consideration for terminal and non-terminal (non intermedaite) steps
|
||||
// // see the JCA. May need to update the cipher operations similarly
|
||||
// // ALSO SEE cipher for how we currently model initialization of the algorithm through an init call
|
||||
// class EVP_DigestUpdate_Operation extends EVP_Hash_Operation {
|
||||
// EVP_DigestUpdate_Operation() {
|
||||
// this.(Call).getTarget().getName() = "EVP_DigestUpdate" and
|
||||
// isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
// }
|
||||
// override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
|
||||
// this.getInitCall().getAlgorithmArg() = result
|
||||
// }
|
||||
// }
|
||||
// class EVP_DigestFinal_Variants_Operation extends EVP_Hash_Operation {
|
||||
// EVP_DigestFinal_Variants_Operation() {
|
||||
// this.(Call).getTarget().getName() in [
|
||||
// "EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
|
||||
// ] and
|
||||
// isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
// }
|
||||
// override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
|
||||
// this.getInitCall().getAlgorithmArg() = result
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,21 @@
|
||||
import experimental.quantum.Language
|
||||
|
||||
abstract class OpenSSLOperation extends Crypto::OperationInstance instanceof Call {
|
||||
abstract Expr getInputArg();
|
||||
|
||||
/**
|
||||
* Can be an argument of a call or a return value of a function.
|
||||
*/
|
||||
abstract Expr getOutputArg();
|
||||
|
||||
DataFlow::Node getInputNode() {
|
||||
// Assumed to be default to asExpr
|
||||
result.asExpr() = this.getInputArg()
|
||||
}
|
||||
|
||||
DataFlow::Node getOutputNode() {
|
||||
if exists(Call c | c.getAnArgument() = this)
|
||||
then result.asDefiningArgument() = this
|
||||
else result.asExpr() = this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import OpenSSLOperationBase
|
||||
import EVPCipherOperation
|
||||
import EVPHashOperation
|
||||
18
cpp/ql/lib/experimental/quantum/OpenSSL/Random.qll
Normal file
18
cpp/ql/lib/experimental/quantum/OpenSSL/Random.qll
Normal file
@@ -0,0 +1,18 @@
|
||||
import cpp
|
||||
private import experimental.quantum.Language
|
||||
private import LibraryDetector
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
class OpenSSLRandomNumberGeneratorInstance extends Crypto::RandomNumberGenerationInstance instanceof Call
|
||||
{
|
||||
OpenSSLRandomNumberGeneratorInstance() {
|
||||
this.(Call).getTarget().getName() in ["RAND_bytes", "RAND_pseudo_bytes"] and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
}
|
||||
|
||||
override Crypto::DataFlowNode getOutputNode() {
|
||||
result.asDefiningArgument() = this.(Call).getArgument(0)
|
||||
}
|
||||
|
||||
override string getGeneratorName() { result = this.(Call).getTarget().getName() }
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 4.3.1-dev
|
||||
version: 4.3.2-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
@@ -8,6 +8,7 @@ upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/dataflow: ${workspace}
|
||||
codeql/mad: ${workspace}
|
||||
codeql/quantum: ${workspace}
|
||||
codeql/rangeanalysis: ${workspace}
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/typeflow: ${workspace}
|
||||
|
||||
@@ -1567,7 +1567,7 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
|
||||
|
|
||||
exists(Ssa::UseImpl use | use.hasIndexInBlock(useblock, _, sv))
|
||||
or
|
||||
exists(Ssa::DefImpl def | def.hasIndexInBlock(useblock, _, sv))
|
||||
exists(Ssa::DefImpl def | def.hasIndexInBlock(sv, useblock, _))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1814,7 +1814,7 @@ module IteratorFlow {
|
||||
*/
|
||||
private predicate isIteratorWrite(Instruction write, Operand address) {
|
||||
exists(Ssa::DefImpl writeDef, IRBlock bb, int i |
|
||||
writeDef.hasIndexInBlock(bb, i, _) and
|
||||
writeDef.hasIndexInBlock(_, bb, i) and
|
||||
bb.getInstruction(i) = write and
|
||||
address = writeDef.getAddressOperand()
|
||||
)
|
||||
|
||||
@@ -191,7 +191,7 @@ abstract class DefImpl extends TDefImpl {
|
||||
* Holds if this definition (or use) has index `index` in block `block`,
|
||||
* and is a definition (or use) of the variable `sv`
|
||||
*/
|
||||
final predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
|
||||
final predicate hasIndexInBlock(SourceVariable sv, IRBlock block, int index) {
|
||||
this.hasIndexInBlock(block, index) and
|
||||
sv = this.getSourceVariable()
|
||||
}
|
||||
@@ -891,12 +891,12 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
exists(DefImpl def | def.hasIndexInBlock(bb, i, v) |
|
||||
exists(DefImpl def | def.hasIndexInBlock(v, bb, i) |
|
||||
if def.isCertain() then certain = true else certain = false
|
||||
)
|
||||
or
|
||||
exists(GlobalDefImpl global |
|
||||
global.hasIndexInBlock(bb, i, v) and
|
||||
global.hasIndexInBlock(v, bb, i) and
|
||||
certain = true
|
||||
)
|
||||
)
|
||||
@@ -934,10 +934,11 @@ module SsaCached {
|
||||
}
|
||||
|
||||
/** Gets the `DefImpl` corresponding to `def`. */
|
||||
pragma[nomagic]
|
||||
private DefImpl getDefImpl(SsaImpl::Definition def) {
|
||||
exists(SourceVariable sv, IRBlock bb, int i |
|
||||
def.definesAt(sv, bb, i) and
|
||||
result.hasIndexInBlock(bb, i, sv)
|
||||
result.hasIndexInBlock(sv, bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -58,4 +58,12 @@ class IRFunction extends IRFunctionBase {
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Holds if this function may have incomplete def-use information.
|
||||
*
|
||||
* Def-use information may be omitted for a function when it is too expensive
|
||||
* to compute.
|
||||
*/
|
||||
final predicate hasIncompleteSsa() { Construction::hasIncompleteSsa(this) }
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ private newtype TMemoryLocation =
|
||||
*
|
||||
* Some of these memory locations will be filtered out for performance reasons before being passed to SSA construction.
|
||||
*/
|
||||
abstract private class MemoryLocation0 extends TMemoryLocation {
|
||||
abstract class MemoryLocation0 extends TMemoryLocation {
|
||||
final string toString() {
|
||||
if this.isMayAccess()
|
||||
then result = "?" + this.toStringInternal()
|
||||
@@ -874,7 +874,7 @@ private int numberOfOverlappingUses(MemoryLocation0 def) {
|
||||
* Holds if `def` is a busy definition. That is, it has a large number of
|
||||
* overlapping uses.
|
||||
*/
|
||||
private predicate isBusyDef(MemoryLocation0 def) { numberOfOverlappingUses(def) > 1024 }
|
||||
predicate isBusyDef(MemoryLocation0 def) { numberOfOverlappingUses(def) > 1024 }
|
||||
|
||||
/** Holds if `use` is a use that overlaps with a busy definition. */
|
||||
private predicate useOverlapWithBusyDef(MemoryLocation0 use) {
|
||||
|
||||
@@ -731,6 +731,20 @@ private module Cached {
|
||||
or
|
||||
instruction = getChi(result.(UninitializedGroupInstruction))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the def-use information for `f` may have been omitted because it
|
||||
* was too expensive to compute. This happens if one of the memory allocations
|
||||
* in `f` is a busy definition (i.e., it has many different overlapping uses).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
cached
|
||||
predicate hasIncompleteSsa(IRFunction f) {
|
||||
exists(Alias::MemoryLocation0 defLocation |
|
||||
Alias::isBusyDef(pragma[only_bind_into](defLocation)) and
|
||||
defLocation.getIRFunction() = f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
||||
|
||||
@@ -58,4 +58,12 @@ class IRFunction extends IRFunctionBase {
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Holds if this function may have incomplete def-use information.
|
||||
*
|
||||
* Def-use information may be omitted for a function when it is too expensive
|
||||
* to compute.
|
||||
*/
|
||||
final predicate hasIncompleteSsa() { Construction::hasIncompleteSsa(this) }
|
||||
}
|
||||
|
||||
@@ -220,6 +220,8 @@ Instruction getMemoryOperandDefinition(
|
||||
none()
|
||||
}
|
||||
|
||||
predicate hasIncompleteSsa(IRFunction f) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the operand totally overlaps with its definition and consumes the
|
||||
* bit range `[startBitOffset, endBitOffset)`.
|
||||
|
||||
@@ -58,4 +58,12 @@ class IRFunction extends IRFunctionBase {
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() { result.getEnclosingIRFunction() = this }
|
||||
|
||||
/**
|
||||
* Holds if this function may have incomplete def-use information.
|
||||
*
|
||||
* Def-use information may be omitted for a function when it is too expensive
|
||||
* to compute.
|
||||
*/
|
||||
final predicate hasIncompleteSsa() { Construction::hasIncompleteSsa(this) }
|
||||
}
|
||||
|
||||
@@ -731,6 +731,20 @@ private module Cached {
|
||||
or
|
||||
instruction = getChi(result.(UninitializedGroupInstruction))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the def-use information for `f` may have been omitted because it
|
||||
* was too expensive to compute. This happens if one of the memory allocations
|
||||
* in `f` is a busy definition (i.e., it has many different overlapping uses).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
cached
|
||||
predicate hasIncompleteSsa(IRFunction f) {
|
||||
exists(Alias::MemoryLocation0 defLocation |
|
||||
Alias::isBusyDef(pragma[only_bind_into](defLocation)) and
|
||||
defLocation.getIRFunction() = f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
||||
|
||||
@@ -73,6 +73,8 @@ class MemoryLocation extends TMemoryLocation {
|
||||
final predicate canReuseSsa() { canReuseSsaForVariable(var) }
|
||||
}
|
||||
|
||||
class MemoryLocation0 = MemoryLocation;
|
||||
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { none() }
|
||||
|
||||
abstract class VariableGroup extends Unit {
|
||||
@@ -141,3 +143,9 @@ int getStartBitOffset(MemoryLocation location) { none() }
|
||||
|
||||
/** Gets the end bit offset of a `MemoryLocation`, if any. */
|
||||
int getEndBitOffset(MemoryLocation location) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `def` is a busy definition. That is, it has a large number of
|
||||
* overlapping uses.
|
||||
*/
|
||||
predicate isBusyDef(MemoryLocation def) { none() }
|
||||
|
||||
@@ -67,8 +67,13 @@ class Class = Cpp::Class; // Used for inheritance conversions
|
||||
predicate hasCaseEdge(string minValue, string maxValue) { hasCaseEdge(_, minValue, maxValue) }
|
||||
|
||||
predicate hasPositionalArgIndex(int argIndex) {
|
||||
exists(Cpp::FunctionCall call | exists(call.getArgument(argIndex))) or
|
||||
exists(Cpp::FunctionCall call | exists(call.getArgument(argIndex)))
|
||||
or
|
||||
exists(Cpp::BuiltInOperation op | exists(op.getChild(argIndex)))
|
||||
or
|
||||
// Ensure we are always able to output the argument of a call to the delete operator.
|
||||
exists(Cpp::DeleteExpr d) and
|
||||
argIndex = 0
|
||||
}
|
||||
|
||||
predicate hasAsmOperandIndex(int operandIndex) {
|
||||
|
||||
@@ -112,7 +112,14 @@ module SemanticExprConfig {
|
||||
}
|
||||
|
||||
/** Holds if no range analysis should be performed on the phi edges in `f`. */
|
||||
private predicate excludeFunction(Cpp::Function f) { count(f.getEntryPoint()) > 1 }
|
||||
private predicate excludeFunction(Cpp::Function f) {
|
||||
count(f.getEntryPoint()) > 1
|
||||
or
|
||||
exists(IR::IRFunction irFunction |
|
||||
irFunction.getFunction() = f and
|
||||
irFunction.hasIncompleteSsa()
|
||||
)
|
||||
}
|
||||
|
||||
SemType getUnknownExprType(Expr expr) { result = getSemanticType(expr.getResultIRType()) }
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
## 1.4.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The tag `external/cwe/cwe-14` has been removed from `cpp/memset-may-be-deleted` and the tag `external/cwe/cwe-014` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cpp/count-untrusted-data-external-api` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cpp/count-untrusted-data-external-api-ir` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cpp/untrusted-data-to-external-api-ir` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cpp/untrusted-data-to-external-api` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cpp/late-check-of-function-argument` and the tag `external/cwe/cwe-020` has been added.
|
||||
|
||||
## 1.3.9
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
## 1.4.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The tag `external/cwe/cwe-14` has been removed from `cpp/memset-may-be-deleted` and the tag `external/cwe/cwe-014` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cpp/count-untrusted-data-external-api` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cpp/count-untrusted-data-external-api-ir` and the tag `external/cwe/cwe-020` has been added.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.3.9
|
||||
lastReleaseVersion: 1.4.0
|
||||
|
||||
23
cpp/ql/src/experimental/quantum/PrintCBOMGraph.ql
Normal file
23
cpp/ql/src/experimental/quantum/PrintCBOMGraph.ql
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @name Print CBOM Graph
|
||||
* @description Outputs a graph representation of the cryptographic bill of materials.
|
||||
* This query only supports DGML output, as CodeQL DOT output omits properties.
|
||||
* @kind graph
|
||||
* @id cpp/print-cbom-graph
|
||||
* @tags quantum
|
||||
* experimental
|
||||
*/
|
||||
|
||||
import experimental.quantum.Language
|
||||
|
||||
query predicate nodes(Crypto::NodeBase node, string key, string value) {
|
||||
Crypto::nodes_graph_impl(node, key, value)
|
||||
}
|
||||
|
||||
query predicate edges(Crypto::NodeBase source, Crypto::NodeBase target, string key, string value) {
|
||||
Crypto::edges_graph_impl(source, target, key, value)
|
||||
}
|
||||
|
||||
query predicate graphProperties(string key, string value) {
|
||||
key = "semmle.graphKind" and value = "graph"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.3.10-dev
|
||||
version: 1.4.1-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -10,5 +10,5 @@ import internal.CaptureModels
|
||||
import SummaryModels
|
||||
|
||||
from DataFlowSummaryTargetApi api, string flow
|
||||
where flow = ContentSensitive::captureFlow(api, _)
|
||||
where flow = ContentSensitive::captureFlow(api, _, _, _, _)
|
||||
select flow order by flow
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
import os.path
|
||||
import subprocess
|
||||
|
||||
# Add Model as Data script directory to sys.path.
|
||||
gitroot = subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode("utf-8").strip()
|
||||
madpath = os.path.join(gitroot, "misc/scripts/models-as-data/")
|
||||
sys.path.append(madpath)
|
||||
|
||||
import generate_flow_model as model
|
||||
|
||||
language = "cpp"
|
||||
model.Generator.make(language).run()
|
||||
@@ -189,15 +189,15 @@ module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<Cpp::Lo
|
||||
)
|
||||
}
|
||||
|
||||
string parameterAccess(Parameter p) { parameterContentAccessImpl(p, result) }
|
||||
string parameterApproximateAccess(Parameter p) { parameterContentAccessImpl(p, result) }
|
||||
|
||||
string parameterContentAccess(Parameter p) { parameterContentAccessImpl(p, result) }
|
||||
string parameterExactAccess(Parameter p) { parameterContentAccessImpl(p, result) }
|
||||
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsOutput(Callable c, DataFlowPrivate::Position pos) {
|
||||
string paramReturnNodeAsExactOutput(Callable c, DataFlowPrivate::Position pos) {
|
||||
exists(Parameter p |
|
||||
p.isSourceParameterOf(c, pos) and
|
||||
result = parameterAccess(p)
|
||||
result = parameterExactAccess(p)
|
||||
)
|
||||
or
|
||||
pos.getArgumentIndex() = -1 and
|
||||
@@ -206,8 +206,8 @@ module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<Cpp::Lo
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsContentOutput(Callable c, DataFlowPrivate::ParameterPosition pos) {
|
||||
result = paramReturnNodeAsOutput(c, pos)
|
||||
string paramReturnNodeAsApproximateOutput(Callable c, DataFlowPrivate::ParameterPosition pos) {
|
||||
result = paramReturnNodeAsExactOutput(c, pos)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
||||
@@ -4,7 +4,9 @@ import SummaryModels
|
||||
import InlineModelsAsDataTest
|
||||
|
||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||
string getCapturedModel(MadRelevantFunction c) { result = ContentSensitive::captureFlow(c, _) }
|
||||
string getCapturedModel(MadRelevantFunction c) {
|
||||
result = ContentSensitive::captureFlow(c, _, _, _, _)
|
||||
}
|
||||
|
||||
string getKind() { result = "contentbased-summary" }
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import SummaryModels
|
||||
import InlineModelsAsDataTest
|
||||
|
||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||
string getCapturedModel(MadRelevantFunction c) { result = Heuristic::captureFlow(c) }
|
||||
string getCapturedModel(MadRelevantFunction c) { result = Heuristic::captureFlow(c, _) }
|
||||
|
||||
string getKind() { result = "heuristic-summary" }
|
||||
}
|
||||
|
||||
@@ -10,32 +10,32 @@ namespace Models {
|
||||
//No model as destructors are excluded from model generation.
|
||||
~BasicFlow() = default;
|
||||
|
||||
//heuristic-summary=Models;BasicFlow;true;returnThis;(int *);;Argument[-1];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnThis;(int *);;Argument[-1];ReturnValue[*];value;df-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnThis;(int *);;Argument[-1];ReturnValue[*];value;dfc-generated
|
||||
BasicFlow* returnThis(int* input) {
|
||||
return this;
|
||||
}
|
||||
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[0];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[*0];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[0];ReturnValue;value;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[*0];ReturnValue[*];value;df-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[0];ReturnValue;value;dfc-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[*0];ReturnValue[*];value;dfc-generated
|
||||
int* returnParam0(int* input0, int* input1) {
|
||||
return input0;
|
||||
}
|
||||
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[1];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[*1];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[1];ReturnValue;value;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[*1];ReturnValue[*];value;df-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[1];ReturnValue;value;dfc-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[*1];ReturnValue[*];value;dfc-generated
|
||||
int* returnParam1(int* input0, int* input1) {
|
||||
return input1;
|
||||
}
|
||||
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[1];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*1];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[2];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*2];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[1];ReturnValue;value;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*1];ReturnValue[*];value;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[2];ReturnValue;value;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*2];ReturnValue[*];value;df-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[1];ReturnValue;value;dfc-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*1];ReturnValue[*];value;dfc-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[2];ReturnValue;value;dfc-generated
|
||||
@@ -46,9 +46,9 @@ namespace Models {
|
||||
|
||||
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];Argument[*1];taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[1];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];Argument[*1];taint;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];ReturnValue[*];value;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[1];ReturnValue;value;df-generated
|
||||
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];Argument[*1];value;df-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];Argument[*1];taint;dfc-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];ReturnValue[*];taint;dfc-generated
|
||||
//contentbased-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];ReturnValue[*];value;dfc-generated
|
||||
@@ -79,14 +79,14 @@ namespace Models {
|
||||
struct TemplatedFlow {
|
||||
T tainted;
|
||||
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnThis;(T);;Argument[-1];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnThis;(T);;Argument[-1];ReturnValue[*];value;df-generated
|
||||
//contentbased-summary=Models;TemplatedFlow<T>;true;template_returnThis;(T);;Argument[-1];ReturnValue[*];value;dfc-generated
|
||||
TemplatedFlow<T>* template_returnThis(T input) {
|
||||
return this;
|
||||
}
|
||||
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[0];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[*0];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[0];ReturnValue;value;df-generated
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[*0];ReturnValue[*];value;df-generated
|
||||
//contentbased-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[0];ReturnValue;value;dfc-generated
|
||||
//contentbased-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[*0];ReturnValue[*];value;dfc-generated
|
||||
T* template_returnParam0(T* input0, T* input1) {
|
||||
@@ -105,8 +105,8 @@ namespace Models {
|
||||
return tainted;
|
||||
}
|
||||
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[0];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[*0];ReturnValue[*];taint;df-generated
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[0];ReturnValue;value;df-generated
|
||||
//heuristic-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[*0];ReturnValue[*];value;df-generated
|
||||
//contentbased-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[0];ReturnValue;value;dfc-generated
|
||||
//contentbased-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[*0];ReturnValue[*];value;dfc-generated
|
||||
template<typename U>
|
||||
@@ -130,7 +130,7 @@ namespace Models {
|
||||
}
|
||||
|
||||
//heuristic-summary=;;true;toplevel_function;(int *);;Argument[0];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=;;true;toplevel_function;(int *);;Argument[*0];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=;;true;toplevel_function;(int *);;Argument[*0];ReturnValue;value;df-generated
|
||||
//heuristic-summary=;;true;toplevel_function;(int *);;Argument[0];Argument[*0];taint;df-generated
|
||||
//contentbased-summary=;;true;toplevel_function;(int *);;Argument[0];Argument[*0];taint;dfc-generated
|
||||
//contentbased-summary=;;true;toplevel_function;(int *);;Argument[0];ReturnValue;taint;dfc-generated
|
||||
@@ -145,13 +145,13 @@ static int static_toplevel_function(int* p) {
|
||||
}
|
||||
|
||||
struct NonFinalStruct {
|
||||
//heuristic-summary=;NonFinalStruct;true;public_not_final_member_function;(int);;Argument[0];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=;NonFinalStruct;true;public_not_final_member_function;(int);;Argument[0];ReturnValue;value;df-generated
|
||||
//contentbased-summary=;NonFinalStruct;true;public_not_final_member_function;(int);;Argument[0];ReturnValue;value;dfc-generated
|
||||
virtual int public_not_final_member_function(int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
//heuristic-summary=;NonFinalStruct;false;public_final_member_function;(int);;Argument[0];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=;NonFinalStruct;false;public_final_member_function;(int);;Argument[0];ReturnValue;value;df-generated
|
||||
//contentbased-summary=;NonFinalStruct;false;public_final_member_function;(int);;Argument[0];ReturnValue;value;dfc-generated
|
||||
virtual int public_final_member_function(int x) final {
|
||||
return x;
|
||||
@@ -171,13 +171,13 @@ protected:
|
||||
};
|
||||
|
||||
struct FinalStruct final {
|
||||
//heuristic-summary=;FinalStruct;false;public_not_final_member_function_2;(int);;Argument[0];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=;FinalStruct;false;public_not_final_member_function_2;(int);;Argument[0];ReturnValue;value;df-generated
|
||||
//contentbased-summary=;FinalStruct;false;public_not_final_member_function_2;(int);;Argument[0];ReturnValue;value;dfc-generated
|
||||
virtual int public_not_final_member_function_2(int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
//heuristic-summary=;FinalStruct;false;public_final_member_function_2;(int);;Argument[0];ReturnValue;taint;df-generated
|
||||
//heuristic-summary=;FinalStruct;false;public_final_member_function_2;(int);;Argument[0];ReturnValue;value;df-generated
|
||||
//contentbased-summary=;FinalStruct;false;public_final_member_function_2;(int);;Argument[0];ReturnValue;value;dfc-generated
|
||||
virtual int public_final_member_function_2(int x) final {
|
||||
return x;
|
||||
@@ -211,7 +211,7 @@ struct HasInt {
|
||||
//contentbased-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[*1];Argument[*0];value;dfc-generated
|
||||
//heuristic-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[1];Argument[*0];taint;df-generated
|
||||
//heuristic-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[1];Argument[*1];taint;df-generated
|
||||
//heuristic-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[*1];Argument[*0];taint;df-generated
|
||||
//heuristic-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[*1];Argument[*0];value;df-generated
|
||||
int copy_struct(HasInt *out, const HasInt *in) {
|
||||
*out = *in;
|
||||
return 1;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#-----| [CopyAssignmentOperator] __va_list_tag& __va_list_tag::operator=(__va_list_tag const&)
|
||||
#-----| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const __va_list_tag &
|
||||
#-----| [MoveAssignmentOperator] __va_list_tag& __va_list_tag::operator=(__va_list_tag&&)
|
||||
#-----| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] __va_list_tag &&
|
||||
#-----| [Operator,TopLevelFunction] void operator delete(void*)
|
||||
#-----| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [VoidPointerType] void *
|
||||
test.cpp:
|
||||
# 5| [TopLevelFunction] void foo(int*)
|
||||
# 5| <params>:
|
||||
# 5| getParameter(0): [Parameter] x
|
||||
# 5| Type = [IntPointerType] int *
|
||||
# 5| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 6| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 6| getExpr(): [DeleteExpr] delete
|
||||
# 6| Type = [VoidType] void
|
||||
# 6| ValueCategory = prvalue
|
||||
# 6| getExprWithReuse(): [VariableAccess] x
|
||||
# 6| Type = [IntPointerType] int *
|
||||
# 6| ValueCategory = prvalue(load)
|
||||
# 7| getStmt(1): [ReturnStmt] return ...
|
||||
# 9| [TopLevelFunction] void bar()
|
||||
# 9| <params>:
|
||||
# 11| [TopLevelFunction] void jazz()
|
||||
# 11| <params>:
|
||||
# 11| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 12| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 12| getExpr(): [FunctionCall] call to bar
|
||||
# 12| Type = [VoidType] void
|
||||
# 12| ValueCategory = prvalue
|
||||
# 13| getStmt(1): [ReturnStmt] return ...
|
||||
11
cpp/ql/test/library-tests/ir/no-function-calls/PrintAST.ql
Normal file
11
cpp/ql/test/library-tests/ir/no-function-calls/PrintAST.ql
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.PrintAST
|
||||
private import PrintConfig
|
||||
|
||||
private class PrintConfig extends PrintAstConfiguration {
|
||||
override predicate shouldPrintDeclaration(Declaration decl) { shouldDumpDeclaration(decl) }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
private import cpp
|
||||
|
||||
/**
|
||||
* Holds if the specified location is in standard headers.
|
||||
*/
|
||||
predicate locationIsInStandardHeaders(Location loc) {
|
||||
loc.getFile().getAbsolutePath().regexpMatch(".*/include/[^/]+")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the AST or IR for the specified declaration should be printed in the test output.
|
||||
*
|
||||
* This predicate excludes declarations defined in standard headers.
|
||||
*/
|
||||
predicate shouldDumpDeclaration(Declaration decl) {
|
||||
not locationIsInStandardHeaders(decl.getLocation()) and
|
||||
(
|
||||
decl instanceof Function
|
||||
or
|
||||
decl.(GlobalOrNamespaceVariable).hasInitializer()
|
||||
or
|
||||
decl.(StaticLocalVariable).hasInitializer()
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
test.cpp:
|
||||
# 5| void foo(int*)
|
||||
# 5| Block 0
|
||||
# 5| v5_1(void) = EnterFunction :
|
||||
# 5| m5_2(unknown) = AliasedDefinition :
|
||||
# 5| m5_3(unknown) = InitializeNonLocal :
|
||||
# 5| m5_4(unknown) = Chi : total:m5_2, partial:m5_3
|
||||
# 5| r5_5(glval<int *>) = VariableAddress[x] :
|
||||
# 5| m5_6(int *) = InitializeParameter[x] : &:r5_5
|
||||
# 5| r5_7(int *) = Load[x] : &:r5_5, m5_6
|
||||
# 5| m5_8(unknown) = InitializeIndirection[x] : &:r5_7
|
||||
# 5| m5_9(unknown) = Chi : total:m5_4, partial:m5_8
|
||||
# 6| r6_1(glval<unknown>) = FunctionAddress[operator delete] :
|
||||
# 6| r6_2(glval<int *>) = VariableAddress[x] :
|
||||
# 6| r6_3(int *) = Load[x] : &:r6_2, m5_6
|
||||
# 6| v6_4(void) = Call[operator delete] : func:r6_1, 0:r6_3
|
||||
# 6| m6_5(unknown) = ^CallSideEffect : ~m5_9
|
||||
# 6| m6_6(unknown) = Chi : total:m5_9, partial:m6_5
|
||||
# 7| v7_1(void) = NoOp :
|
||||
# 5| v5_10(void) = ReturnIndirection[x] : &:r5_7, ~m6_6
|
||||
# 5| v5_11(void) = ReturnVoid :
|
||||
# 5| v5_12(void) = AliasedUse : ~m6_6
|
||||
# 5| v5_13(void) = ExitFunction :
|
||||
|
||||
# 11| void jazz()
|
||||
# 11| Block 0
|
||||
# 11| v11_1(void) = EnterFunction :
|
||||
# 11| m11_2(unknown) = AliasedDefinition :
|
||||
# 11| m11_3(unknown) = InitializeNonLocal :
|
||||
# 11| m11_4(unknown) = Chi : total:m11_2, partial:m11_3
|
||||
# 12| r12_1(glval<unknown>) = FunctionAddress[bar] :
|
||||
# 12| v12_2(void) = Call[bar] : func:r12_1
|
||||
# 12| m12_3(unknown) = ^CallSideEffect : ~m11_4
|
||||
# 12| m12_4(unknown) = Chi : total:m11_4, partial:m12_3
|
||||
# 13| v13_1(void) = NoOp :
|
||||
# 11| v11_5(void) = ReturnVoid :
|
||||
# 11| v11_6(void) = AliasedUse : ~m12_4
|
||||
# 11| v11_7(void) = ExitFunction :
|
||||
11
cpp/ql/test/library-tests/ir/no-function-calls/aliased_ir.ql
Normal file
11
cpp/ql/test/library-tests/ir/no-function-calls/aliased_ir.ql
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.aliased_ssa.PrintIR
|
||||
private import PrintConfig
|
||||
|
||||
private class PrintConfig extends PrintIRConfiguration {
|
||||
override predicate shouldPrintDeclaration(Declaration decl) { shouldDumpDeclaration(decl) }
|
||||
}
|
||||
13
cpp/ql/test/library-tests/ir/no-function-calls/test.cpp
Normal file
13
cpp/ql/test/library-tests/ir/no-function-calls/test.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
// Test for edge case, where we have a database without any function calls or
|
||||
// where none of the function calls have any arguments, but where we do have
|
||||
// a delete expression.
|
||||
|
||||
void foo(int* x) {
|
||||
delete x;
|
||||
}
|
||||
|
||||
void bar();
|
||||
|
||||
void jazz() {
|
||||
bar();
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.40
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.39
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.40
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.39
|
||||
lastReleaseVersion: 1.7.40
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.40-dev
|
||||
version: 1.7.41-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.40
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.39
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.40
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.39
|
||||
lastReleaseVersion: 1.7.40
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.40-dev
|
||||
version: 1.7.41-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
ql/csharp/ql/src/API Abuse/CallToGCCollect.ql
|
||||
ql/csharp/ql/src/API Abuse/FormatInvalid.ql
|
||||
ql/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql
|
||||
ql/csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 5.1.6
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 5.1.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
3
csharp/ql/lib/change-notes/released/5.1.6.md
Normal file
3
csharp/ql/lib/change-notes/released/5.1.6.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 5.1.6
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 5.1.5
|
||||
lastReleaseVersion: 5.1.6
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 5.1.6-dev
|
||||
version: 5.1.7-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -233,15 +233,28 @@ class InvalidFormatString extends StringLiteral {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method call to a method that parses a format string, for example a call
|
||||
* to `string.Format()`.
|
||||
*/
|
||||
abstract private class FormatStringParseCallImpl extends MethodCall {
|
||||
/**
|
||||
* Gets the expression used as the format string.
|
||||
*/
|
||||
abstract Expr getFormatExpr();
|
||||
}
|
||||
|
||||
final class FormatStringParseCall = FormatStringParseCallImpl;
|
||||
|
||||
/**
|
||||
* A method call to a method that formats a string, for example a call
|
||||
* to `string.Format()`.
|
||||
*/
|
||||
class FormatCall extends MethodCall {
|
||||
class FormatCall extends FormatStringParseCallImpl {
|
||||
FormatCall() { this.getTarget() instanceof FormatMethod }
|
||||
|
||||
/** Gets the expression used as the format string. */
|
||||
Expr getFormatExpr() { result = this.getArgument(this.getFormatArgument()) }
|
||||
override Expr getFormatExpr() { result = this.getArgument(this.getFormatArgument()) }
|
||||
|
||||
/** Gets the argument number containing the format string. */
|
||||
int getFormatArgument() { result = this.getTarget().(FormatMethod).getFormatArgument() }
|
||||
@@ -289,3 +302,14 @@ class FormatCall extends MethodCall {
|
||||
result = this.getArgument(this.getFirstArgument() + index)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method call to `System.Text.CompositeFormat.Parse`.
|
||||
*/
|
||||
class ParseFormatStringCall extends FormatStringParseCallImpl {
|
||||
ParseFormatStringCall() {
|
||||
this.getTarget() = any(SystemTextCompositeFormatClass x).getParseMethod()
|
||||
}
|
||||
|
||||
override Expr getFormatExpr() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* @id cs/call-to-gc
|
||||
* @tags efficiency
|
||||
* maintainability
|
||||
* quality
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
@@ -16,22 +16,6 @@ import semmle.code.csharp.frameworks.system.Text
|
||||
import semmle.code.csharp.frameworks.Format
|
||||
import FormatFlow::PathGraph
|
||||
|
||||
abstract class FormatStringParseCall extends MethodCall {
|
||||
abstract Expr getFormatExpr();
|
||||
}
|
||||
|
||||
class OrdinaryFormatCall extends FormatStringParseCall instanceof FormatCall {
|
||||
override Expr getFormatExpr() { result = FormatCall.super.getFormatExpr() }
|
||||
}
|
||||
|
||||
class ParseFormatStringCall extends FormatStringParseCall {
|
||||
ParseFormatStringCall() {
|
||||
this.getTarget() = any(SystemTextCompositeFormatClass x).getParseMethod()
|
||||
}
|
||||
|
||||
override Expr getFormatExpr() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
module FormatInvalidConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
## 1.2.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The tag `external/cwe/cwe-13` has been removed from `cs/password-in-configuration` and the tag `external/cwe/cwe-013` has been added.
|
||||
* The tag `external/cwe/cwe-11` has been removed from `cs/web/debug-binary` and the tag `external/cwe/cwe-011` has been added.
|
||||
* The tag `external/cwe/cwe-16` has been removed from `cs/web/large-max-request-length` and the tag `external/cwe/cwe-016` has been added.
|
||||
* The tag `external/cwe/cwe-16` has been removed from `cs/web/request-validation-disabled` and the tag `external/cwe/cwe-016` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cs/count-untrusted-data-external-api` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cs/serialization-check-bypass` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cs/untrusted-data-to-external-api` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-12` has been removed from `cs/web/missing-global-error-handler` and the tag `external/cwe/cwe-012` has been added.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Changed the precision of the `cs/equality-on-floats` query from medium to high.
|
||||
|
||||
## 1.1.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -20,7 +20,7 @@ module FormatStringConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(FormatCall call | call.hasInsertions()).getFormatExpr()
|
||||
sink.asExpr() = any(FormatStringParseCall call).getFormatExpr()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The precision of the query `cs/uncontrolled-format-string` has been improved (false negative reduction). Calls to `System.Text.CompositeFormat.Parse` are now considered a format like method call.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Changed the precision of the `cs/equality-on-floats` query from medium to high.
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
## 1.2.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The tag `external/cwe/cwe-13` has been removed from `cs/password-in-configuration` and the tag `external/cwe/cwe-013` has been added.
|
||||
* The tag `external/cwe/cwe-11` has been removed from `cs/web/debug-binary` and the tag `external/cwe/cwe-011` has been added.
|
||||
@@ -10,3 +10,7 @@ category: queryMetadata
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cs/serialization-check-bypass` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-20` has been removed from `cs/untrusted-data-to-external-api` and the tag `external/cwe/cwe-020` has been added.
|
||||
* The tag `external/cwe/cwe-12` has been removed from `cs/web/missing-global-error-handler` and the tag `external/cwe/cwe-012` has been added.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Changed the precision of the `cs/equality-on-floats` query from medium to high.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.1.2
|
||||
lastReleaseVersion: 1.2.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 1.1.3-dev
|
||||
version: 1.2.1-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -10,5 +10,5 @@ import internal.CaptureModels
|
||||
import SummaryModels
|
||||
|
||||
from DataFlowSummaryTargetApi api, string flow
|
||||
where flow = ContentSensitive::captureFlow(api, _)
|
||||
where flow = ContentSensitive::captureFlow(api, _, _, _, _)
|
||||
select flow order by flow
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
import os.path
|
||||
import subprocess
|
||||
|
||||
# Add Model as Data script directory to sys.path.
|
||||
gitroot = subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode("utf-8").strip()
|
||||
madpath = os.path.join(gitroot, "misc/scripts/models-as-data/")
|
||||
sys.path.append(madpath)
|
||||
|
||||
import generate_flow_model as model
|
||||
|
||||
language = "csharp"
|
||||
model.Generator.make(language).run()
|
||||
@@ -15,7 +15,7 @@ import PartialFlow::PartialPathGraph
|
||||
|
||||
int explorationLimit() { result = 3 }
|
||||
|
||||
module PartialFlow = Heuristic::PropagateFlow::FlowExplorationFwd<explorationLimit/0>;
|
||||
module PartialFlow = Heuristic::PropagateTaintFlow::FlowExplorationFwd<explorationLimit/0>;
|
||||
|
||||
from
|
||||
PartialFlow::PartialPathNode source, PartialFlow::PartialPathNode sink,
|
||||
|
||||
@@ -11,16 +11,15 @@
|
||||
import csharp
|
||||
import utils.modelgenerator.internal.CaptureModels
|
||||
import SummaryModels
|
||||
import Heuristic
|
||||
import PropagateFlow::PathGraph
|
||||
import Heuristic::PropagateTaintFlow::PathGraph
|
||||
|
||||
from
|
||||
PropagateFlow::PathNode source, PropagateFlow::PathNode sink, DataFlowSummaryTargetApi api,
|
||||
DataFlow::Node p, DataFlow::Node returnNodeExt
|
||||
Heuristic::PropagateTaintFlow::PathNode source, Heuristic::PropagateTaintFlow::PathNode sink,
|
||||
DataFlowSummaryTargetApi api, DataFlow::Node p, DataFlow::Node returnNodeExt
|
||||
where
|
||||
PropagateFlow::flowPath(source, sink) and
|
||||
Heuristic::PropagateTaintFlow::flowPath(source, sink) and
|
||||
p = source.getNode() and
|
||||
returnNodeExt = sink.getNode() and
|
||||
exists(captureThroughFlow0(api, p, returnNodeExt))
|
||||
Heuristic::captureThroughFlow0(api, p, returnNodeExt)
|
||||
select sink.getNode(), source, sink, "There is flow from $@ to the $@.", source.getNode(),
|
||||
"parameter", sink.getNode(), "return value"
|
||||
|
||||
@@ -124,13 +124,13 @@ module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<Locatio
|
||||
|
||||
string qualifierString() { result = "Argument[this]" }
|
||||
|
||||
string parameterAccess(CS::Parameter p) {
|
||||
string parameterApproximateAccess(CS::Parameter p) {
|
||||
if Collections::isCollectionType(p.getType())
|
||||
then result = "Argument[" + p.getPosition() + "].Element"
|
||||
else result = "Argument[" + p.getPosition() + "]"
|
||||
}
|
||||
|
||||
string parameterContentAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
|
||||
string parameterExactAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
|
||||
|
||||
private signature string parameterAccessSig(Parameter p);
|
||||
|
||||
@@ -145,13 +145,13 @@ module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<Locatio
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
|
||||
result = ParamReturnNodeAsOutput<parameterAccess/1>::paramReturnNodeAsOutput(c, pos)
|
||||
string paramReturnNodeAsApproximateOutput(CS::Callable c, ParameterPosition pos) {
|
||||
result = ParamReturnNodeAsOutput<parameterApproximateAccess/1>::paramReturnNodeAsOutput(c, pos)
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) {
|
||||
result = ParamReturnNodeAsOutput<parameterContentAccess/1>::paramReturnNodeAsOutput(c, pos)
|
||||
string paramReturnNodeAsExactOutput(Callable c, ParameterPosition pos) {
|
||||
result = ParamReturnNodeAsOutput<parameterExactAccess/1>::paramReturnNodeAsOutput(c, pos)
|
||||
}
|
||||
|
||||
ParameterPosition getReturnKindParamPosition(ReturnKind kind) {
|
||||
|
||||
@@ -39,7 +39,7 @@ private predicate localTypeParameter(Callable callable, TypeParameter tp) {
|
||||
*/
|
||||
private predicate parameter(Callable callable, string input, TypeParameter tp) {
|
||||
exists(Parameter p |
|
||||
input = ModelGeneratorInput::parameterAccess(p) and
|
||||
input = ModelGeneratorInput::parameterApproximateAccess(p) and
|
||||
p = callable.getAParameter() and
|
||||
(
|
||||
// Parameter of type tp
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
semmle-extractor-options: ${testdir}/../../resources/stubs/System.Web.cs
|
||||
semmle-extractor-options: ${testdir}/../../resources/stubs/System.Web.cs
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user