mirror of
https://github.com/github/codeql.git
synced 2026-05-31 03:21:23 +02:00
Compare commits
413 Commits
testing/2/
...
esbena/sub
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79947956bc | ||
|
|
ba27a0d515 | ||
|
|
32d82380f1 | ||
|
|
fe2468e7d0 | ||
|
|
20c3984872 | ||
|
|
0e3369f93f | ||
|
|
80c5e1ea77 | ||
|
|
c30e004506 | ||
|
|
ae8e237f2c | ||
|
|
d723905035 | ||
|
|
7700210ed2 | ||
|
|
53561008a1 | ||
|
|
39bca2d4bb | ||
|
|
0ef83b3c74 | ||
|
|
d56a9f0781 | ||
|
|
fb0016e4f6 | ||
|
|
9a2ac65f53 | ||
|
|
915352861d | ||
|
|
69c3e62965 | ||
|
|
15ec0a10c9 | ||
|
|
61676277e8 | ||
|
|
0cea3f8531 | ||
|
|
1297acf5b1 | ||
|
|
9080e84fc9 | ||
|
|
5e921784fb | ||
|
|
b1ad61e27d | ||
|
|
2ddcd1d9cc | ||
|
|
8f70b55158 | ||
|
|
2edc70da79 | ||
|
|
fe57cd0784 | ||
|
|
6ab2de10e3 | ||
|
|
ed9502fd0b | ||
|
|
adb47399c7 | ||
|
|
3c34638438 | ||
|
|
9f683b8630 | ||
|
|
cf7f355fc4 | ||
|
|
64fa6c8bbd | ||
|
|
5c0085880f | ||
|
|
e2a8569940 | ||
|
|
8f852f2e7d | ||
|
|
fa1e8ee426 | ||
|
|
822ba2ae59 | ||
|
|
116025c569 | ||
|
|
a4d0ef6350 | ||
|
|
a9a21aa313 | ||
|
|
1f4fcf1f31 | ||
|
|
a1c1f7b910 | ||
|
|
f38d2e1b89 | ||
|
|
c28004f2a6 | ||
|
|
07172da1bc | ||
|
|
f7b02c01dd | ||
|
|
1d9ee5da3c | ||
|
|
59c43c7904 | ||
|
|
02f73145d6 | ||
|
|
b936e91fe9 | ||
|
|
f6570710e7 | ||
|
|
3b4ea27caf | ||
|
|
09c1c715a3 | ||
|
|
7916bd39b4 | ||
|
|
09974b5176 | ||
|
|
8a0dc31ab0 | ||
|
|
2e8a91efda | ||
|
|
534ea3ecac | ||
|
|
5fcdb9e112 | ||
|
|
286271340e | ||
|
|
e82076d558 | ||
|
|
e300440a8b | ||
|
|
dfcdb4ace8 | ||
|
|
ee2d8f84de | ||
|
|
e5e9c33005 | ||
|
|
06a600c7fb | ||
|
|
f018d83951 | ||
|
|
4cb78ab3c7 | ||
|
|
da096553a2 | ||
|
|
0e4cd7f52f | ||
|
|
1a370bfbbe | ||
|
|
4f31b5a214 | ||
|
|
ada5dcced4 | ||
|
|
e718796f23 | ||
|
|
e1b283c14a | ||
|
|
93380f8cbb | ||
|
|
12fdb3427b | ||
|
|
b8effa3a1c | ||
|
|
4e2c6ff8d7 | ||
|
|
4887c697c9 | ||
|
|
ae6af17c74 | ||
|
|
a31f946d6f | ||
|
|
7780fe9472 | ||
|
|
b6bf4d04ff | ||
|
|
442a4fe9cf | ||
|
|
7a98afe6ec | ||
|
|
a4eb3fd997 | ||
|
|
7d7d90e7e0 | ||
|
|
94b0bc1e35 | ||
|
|
6260768e6a | ||
|
|
c41676a21a | ||
|
|
477d8f8b9a | ||
|
|
96543b8337 | ||
|
|
02915582eb | ||
|
|
8a3aa2c767 | ||
|
|
267fd23b26 | ||
|
|
304d7a4395 | ||
|
|
85bb14f04f | ||
|
|
d54ab640c7 | ||
|
|
4133284bc8 | ||
|
|
aa7a667919 | ||
|
|
5e273238ca | ||
|
|
89bd00a4ec | ||
|
|
6df919a917 | ||
|
|
68d00a829e | ||
|
|
6377e92067 | ||
|
|
e99b1598d1 | ||
|
|
c587dbb72a | ||
|
|
4499048d8e | ||
|
|
877605d31b | ||
|
|
b6968d9260 | ||
|
|
8d6f985aea | ||
|
|
db9f74bc78 | ||
|
|
82483a206e | ||
|
|
38b0ed8176 | ||
|
|
ccd06c78b9 | ||
|
|
7a4382fb69 | ||
|
|
80c8259e34 | ||
|
|
f1cefc8900 | ||
|
|
496f190d70 | ||
|
|
512c10ec59 | ||
|
|
ee75b104eb | ||
|
|
72d0dcdaba | ||
|
|
6521e5165c | ||
|
|
f1266a3e81 | ||
|
|
4c6073ebce | ||
|
|
2378e31c5e | ||
|
|
be16cb4190 | ||
|
|
ce905bba41 | ||
|
|
bc1c22cda2 | ||
|
|
2d947a4f53 | ||
|
|
542d5a2451 | ||
|
|
3b777c2764 | ||
|
|
1872a937d5 | ||
|
|
fd9c1d30f9 | ||
|
|
cf0411e7e2 | ||
|
|
8e1bb4b364 | ||
|
|
0d562d4874 | ||
|
|
48ee4add08 | ||
|
|
0374414798 | ||
|
|
5c44f8bbad | ||
|
|
538df1bb6d | ||
|
|
5cb3543899 | ||
|
|
0e09420e7b | ||
|
|
4489e2bf28 | ||
|
|
2579791f51 | ||
|
|
fe60269fdd | ||
|
|
6ff8e06ace | ||
|
|
e8ac258994 | ||
|
|
f186b93c93 | ||
|
|
8af727734e | ||
|
|
ebd640da04 | ||
|
|
625e889c62 | ||
|
|
57e32b47b7 | ||
|
|
62b0ebf2fe | ||
|
|
e1b2f81f43 | ||
|
|
ef63d9dd47 | ||
|
|
cf3a62d201 | ||
|
|
4a0ab4a050 | ||
|
|
8c6a1be070 | ||
|
|
e38ba27a65 | ||
|
|
ada331588f | ||
|
|
f7bd801e00 | ||
|
|
a1d417d8b6 | ||
|
|
0258dd4fed | ||
|
|
a7ab9fd93b | ||
|
|
f48b47c656 | ||
|
|
57c757c0a6 | ||
|
|
194f918c0b | ||
|
|
c2942b37a7 | ||
|
|
e0fefce2a3 | ||
|
|
e3e8f3d7c4 | ||
|
|
689eda4dae | ||
|
|
1c9f59e491 | ||
|
|
0d992a3d1f | ||
|
|
28f8c1cc11 | ||
|
|
7c332a31a8 | ||
|
|
8a7325268a | ||
|
|
c492b5f2dd | ||
|
|
8bf6fd67d1 | ||
|
|
4bc4e0845d | ||
|
|
d261cec3cd | ||
|
|
f3e5045259 | ||
|
|
56e9eda2b9 | ||
|
|
2c0dcd3a2d | ||
|
|
4dca396106 | ||
|
|
000c1f7ec8 | ||
|
|
7ca0996912 | ||
|
|
9b6501787a | ||
|
|
0918e50b05 | ||
|
|
18e6a5491c | ||
|
|
951ed01d6b | ||
|
|
7c28528eac | ||
|
|
676179620a | ||
|
|
bc9d8cc40f | ||
|
|
691665fca8 | ||
|
|
bece2e8689 | ||
|
|
9a628d4165 | ||
|
|
8006996f46 | ||
|
|
85587413d0 | ||
|
|
c281db6b5b | ||
|
|
ec292ca4e1 | ||
|
|
7d36c23d59 | ||
|
|
b6132d2a0f | ||
|
|
dca39348ab | ||
|
|
fb10af9042 | ||
|
|
7d73808d60 | ||
|
|
aa127b1662 | ||
|
|
0b13da35eb | ||
|
|
01a1d814f4 | ||
|
|
c63f6807c4 | ||
|
|
76781e5d75 | ||
|
|
a08356979f | ||
|
|
eb3f1967a5 | ||
|
|
97b3ebe385 | ||
|
|
b231b1ccaf | ||
|
|
bbec4082c0 | ||
|
|
66637e8c03 | ||
|
|
81d4ec1e98 | ||
|
|
c79ec8c37a | ||
|
|
fdcc6b482d | ||
|
|
7ddece1560 | ||
|
|
6bea7f89a8 | ||
|
|
d3a1dbc0c7 | ||
|
|
e31ca58a2f | ||
|
|
17894db501 | ||
|
|
20900dafc0 | ||
|
|
96f93cefba | ||
|
|
e124a70380 | ||
|
|
0cf309b64e | ||
|
|
2f39ab1977 | ||
|
|
602bb4083c | ||
|
|
333e607536 | ||
|
|
399fab0c6c | ||
|
|
96edc1d349 | ||
|
|
315272839d | ||
|
|
a402bfcfb0 | ||
|
|
5dd7c14d36 | ||
|
|
162c477236 | ||
|
|
e38f65981e | ||
|
|
4d3863461e | ||
|
|
cc63bb55c2 | ||
|
|
75c74d50f9 | ||
|
|
8e653d01a8 | ||
|
|
9c3b72cf3f | ||
|
|
00068d6157 | ||
|
|
e2a14c7616 | ||
|
|
11b92608c7 | ||
|
|
ab07a38c25 | ||
|
|
015519e9e0 | ||
|
|
cd40663ca4 | ||
|
|
74368540ae | ||
|
|
9fe993bec3 | ||
|
|
b5f1296cc2 | ||
|
|
f7ca8e5b39 | ||
|
|
4122fd881f | ||
|
|
843e9ad254 | ||
|
|
40e63a63e2 | ||
|
|
0f5dd40ff1 | ||
|
|
0c2275ddb1 | ||
|
|
3703c5626f | ||
|
|
c3a21daf83 | ||
|
|
06ec3bbbb5 | ||
|
|
9c02b4f21c | ||
|
|
ec3f08037c | ||
|
|
bd2c49fcf0 | ||
|
|
567052f35e | ||
|
|
f0fb065446 | ||
|
|
5fd6dc3b87 | ||
|
|
31550b22b6 | ||
|
|
581d410304 | ||
|
|
e122d81336 | ||
|
|
a1d3667f1c | ||
|
|
3a75c0fde7 | ||
|
|
655470f3da | ||
|
|
de2e8b0b12 | ||
|
|
ad86e576a4 | ||
|
|
b683a3caf8 | ||
|
|
06da5fd05c | ||
|
|
22c4b5113d | ||
|
|
cdef0796e3 | ||
|
|
497f0aa8ab | ||
|
|
9a139ea903 | ||
|
|
57d3f3f482 | ||
|
|
9df5e43fae | ||
|
|
7c8233aade | ||
|
|
5433636d49 | ||
|
|
2a52455619 | ||
|
|
53a291aeae | ||
|
|
6c8ae55a68 | ||
|
|
0f1711fe1e | ||
|
|
ca722dc74c | ||
|
|
db5e0ff7a8 | ||
|
|
3d552d7d5d | ||
|
|
3265d49a98 | ||
|
|
f83456a398 | ||
|
|
c61edc13e7 | ||
|
|
0c534b69eb | ||
|
|
2863a14cd1 | ||
|
|
df1bc1a597 | ||
|
|
95363455af | ||
|
|
f0f60c3b7d | ||
|
|
5d4b542995 | ||
|
|
8d47a7b21d | ||
|
|
832e78c518 | ||
|
|
cf5d1e36fe | ||
|
|
e0b61b2d68 | ||
|
|
c0b579c49f | ||
|
|
7d34ce4dea | ||
|
|
f3acc89900 | ||
|
|
77fd9172fa | ||
|
|
64e4c1ea6d | ||
|
|
d71d6b265a | ||
|
|
4799ba0069 | ||
|
|
188ad6a571 | ||
|
|
9975a18a29 | ||
|
|
a7a50cfc9a | ||
|
|
25203db4e7 | ||
|
|
84c0c09673 | ||
|
|
72ca6b8c5f | ||
|
|
c796cba02f | ||
|
|
7d5bbc3b1e | ||
|
|
9598bb5a68 | ||
|
|
c6ad358751 | ||
|
|
c78f390128 | ||
|
|
73803eaac9 | ||
|
|
50521f7b45 | ||
|
|
cea44e2bee | ||
|
|
3febbec64e | ||
|
|
81ee932e62 | ||
|
|
293400a623 | ||
|
|
ae1072e09f | ||
|
|
a123f62a38 | ||
|
|
811c33b016 | ||
|
|
92fdb7a35f | ||
|
|
f9a617c714 | ||
|
|
51ed824adf | ||
|
|
6be01eac04 | ||
|
|
4350060b0f | ||
|
|
839b9635b9 | ||
|
|
16ae637238 | ||
|
|
4245a38de9 | ||
|
|
fd0d194a8a | ||
|
|
b7f874d1f1 | ||
|
|
c5faddc2a4 | ||
|
|
9f9c9e0e5e | ||
|
|
e239d763dc | ||
|
|
05ab28f11d | ||
|
|
db7b1eea55 | ||
|
|
f515559e56 | ||
|
|
a45e10d64f | ||
|
|
56d99fbd8a | ||
|
|
d1caa75053 | ||
|
|
8ce79e6be8 | ||
|
|
325d6f738c | ||
|
|
5b77e7db8a | ||
|
|
2214caef4b | ||
|
|
7ad2932b3f | ||
|
|
c0c2ae544b | ||
|
|
5fed923af0 | ||
|
|
50db4fd63e | ||
|
|
7560db66fa | ||
|
|
fe22dc45b1 | ||
|
|
6d7ac8de28 | ||
|
|
4c9cc5a21f | ||
|
|
7256faa7eb | ||
|
|
30b30695e4 | ||
|
|
da864bf7f7 | ||
|
|
a96b0011f0 | ||
|
|
1e12a86781 | ||
|
|
2136929164 | ||
|
|
bc6a0fc776 | ||
|
|
2053ee00ab | ||
|
|
18dac9ab8a | ||
|
|
1764aa0caf | ||
|
|
8254d0dd10 | ||
|
|
6d0ba5f97b | ||
|
|
70103967ef | ||
|
|
cada523031 | ||
|
|
2b54ad58b0 | ||
|
|
52d1e45b05 | ||
|
|
5706bc6205 | ||
|
|
eddca7f3f6 | ||
|
|
ab7cd5254a | ||
|
|
9a5fa42dbe | ||
|
|
56b646a74c | ||
|
|
dd01da4938 | ||
|
|
5411123b8a | ||
|
|
57ae1ee3e9 | ||
|
|
1526fff085 | ||
|
|
20f1a74202 | ||
|
|
e0fae764f1 | ||
|
|
7ca6b6f9a6 | ||
|
|
53ad559da5 | ||
|
|
988a871999 | ||
|
|
a3e250aef5 | ||
|
|
50d23f145b | ||
|
|
f3ea72c234 | ||
|
|
40ff16bdaf | ||
|
|
68392e7ae7 | ||
|
|
25c60c455e | ||
|
|
b657301d39 | ||
|
|
e9fdbfabea | ||
|
|
6274dfafdc | ||
|
|
49aa3eb92b | ||
|
|
6d6a243776 | ||
|
|
1a1fee3088 | ||
|
|
a1782182dd |
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@@ -17,3 +17,10 @@ updates:
|
||||
ignore:
|
||||
- dependency-name: '*'
|
||||
update-types: ['version-update:semver-patch', 'version-update:semver-minor']
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "go/extractor"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "github/codeql-go"
|
||||
|
||||
4
.github/workflows/compile-queries.yml
vendored
4
.github/workflows/compile-queries.yml
vendored
@@ -29,9 +29,9 @@ jobs:
|
||||
# run with --check-only if running in a PR (github.sha != main)
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
||||
- name: compile queries - full
|
||||
# do full compile if running on main - this populates the cache
|
||||
if : ${{ github.event_name != 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
||||
|
||||
2
.github/workflows/csharp-qltest.yml
vendored
2
.github/workflows/csharp-qltest.yml
vendored
@@ -91,7 +91,7 @@ jobs:
|
||||
run: |
|
||||
# Generate (Asp)NetCore stubs
|
||||
STUBS_PATH=stubs_output
|
||||
python3 ql/src/Stubs/make_stubs_nuget.py webapp Swashbuckle.AspNetCore.Swagger latest "$STUBS_PATH"
|
||||
python3 ql/src/Stubs/make_stubs_nuget.py webapp Swashbuckle.AspNetCore.Swagger 6.5.0 "$STUBS_PATH"
|
||||
rm -rf ql/test/resources/stubs/_frameworks
|
||||
# Update existing stubs in the repo with the freshly generated ones
|
||||
mv "$STUBS_PATH/output/stubs/_frameworks" ql/test/resources/stubs/
|
||||
|
||||
@@ -498,22 +498,6 @@
|
||||
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsExtensions.qll",
|
||||
"python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsExtensions.qll"
|
||||
],
|
||||
"TaintedFormatStringQuery Ruby/JS": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringQuery.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringQuery.qll"
|
||||
],
|
||||
"TaintedFormatStringCustomizations Ruby/JS": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringCustomizations.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringCustomizations.qll"
|
||||
],
|
||||
"HttpToFileAccessQuery JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessQuery.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessQuery.qll"
|
||||
],
|
||||
"HttpToFileAccessCustomizations JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
|
||||
],
|
||||
"Typo database": [
|
||||
"javascript/ql/src/Expressions/TypoDatabase.qll",
|
||||
"ql/ql/src/codeql_ql/style/TypoDatabase.qll"
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_filegroup")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
alias(
|
||||
name = "dbscheme",
|
||||
actual = "//cpp/ql/lib:dbscheme",
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "dbscheme-stats",
|
||||
actual = "//cpp/ql/lib:dbscheme-stats",
|
||||
)
|
||||
|
||||
pkg_filegroup(
|
||||
name = "db-files",
|
||||
srcs = [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package(default_visibility = ["//cpp:__pkg__"])
|
||||
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files")
|
||||
|
||||
package(default_visibility = ["//cpp:__pkg__"])
|
||||
|
||||
pkg_files(
|
||||
name = "dbscheme",
|
||||
srcs = ["semmlecode.cpp.dbscheme"],
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 0.10.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
|
||||
non-returning in the IR and dataflow.
|
||||
* Treat functions that reach the end of the function as returning in the IR.
|
||||
They used to be treated as unreachable but it is allowed in C.
|
||||
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.
|
||||
|
||||
## 0.9.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Treat functions that reach the end of the function as returning in the IR.
|
||||
They used to be treated as unreachable but it is allowed in C.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
|
||||
non-returning in the IR and dataflow.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Deleted the deprecated `AnalysedString` class, use the new name `AnalyzedString`.
|
||||
* Deleted the deprecated `isBarrierGuard` predicate from the dataflow library and its uses, use `isBarrier` and the `BarrierGuard` module instead.
|
||||
9
cpp/ql/lib/change-notes/released/0.10.0.md
Normal file
9
cpp/ql/lib/change-notes/released/0.10.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 0.10.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
|
||||
non-returning in the IR and dataflow.
|
||||
* Treat functions that reach the end of the function as returning in the IR.
|
||||
They used to be treated as unreachable but it is allowed in C.
|
||||
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.9.3
|
||||
lastReleaseVersion: 0.10.0
|
||||
|
||||
3
cpp/ql/lib/experimental/cryptography/Concepts.qll
Normal file
3
cpp/ql/lib/experimental/cryptography/Concepts.qll
Normal file
@@ -0,0 +1,3 @@
|
||||
import experimental.cryptography.CryptoArtifact
|
||||
import experimental.cryptography.CryptoAlgorithmNames
|
||||
import experimental.cryptography.modules.OpenSSL as OpenSSL
|
||||
239
cpp/ql/lib/experimental/cryptography/CryptoAlgorithmNames.qll
Normal file
239
cpp/ql/lib/experimental/cryptography/CryptoAlgorithmNames.qll
Normal file
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* Names of known cryptographic algorithms.
|
||||
* The names are standardized into upper-case, no spaces, dashes or underscores.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a string to represent generally unknown algorithms.
|
||||
* Predicate is to be used to get a consistent string representation
|
||||
* for unknown algorithms.
|
||||
*/
|
||||
string unknownAlgorithm() { result = "UNKNOWN" }
|
||||
|
||||
string getHashType() { result = "HASH" }
|
||||
|
||||
string getSymmetricEncryptionType() { result = "SYMMETRIC_ENCRYPTION" }
|
||||
|
||||
string getAsymmetricEncryptionType() { result = "ASYMMETRIC_ENCRYPTION" }
|
||||
|
||||
string getKeyDerivationType() { result = "KEY_DERIVATION" }
|
||||
|
||||
string getCipherBlockModeType() { result = "BLOCK_MODE" }
|
||||
|
||||
string getSymmetricPaddingType() { result = "SYMMETRIC_PADDING" }
|
||||
|
||||
string getAsymmetricPaddingType() { result = "ASYMMETRIC_PADDING" }
|
||||
|
||||
string getEllipticCurveType() { result = "ELLIPTIC_CURVE" }
|
||||
|
||||
string getSignatureType() { result = "SIGNATURE" }
|
||||
|
||||
string getKeyExchangeType() { result = "KEY_EXCHANGE" }
|
||||
|
||||
string getAsymmetricType() {
|
||||
result in [
|
||||
getAsymmetricEncryptionType(), getSignatureType(), getKeyExchangeType(),
|
||||
getEllipticCurveType()
|
||||
]
|
||||
}
|
||||
|
||||
predicate isKnownType(string algType) {
|
||||
algType in [
|
||||
getHashType(), getSymmetricEncryptionType(), getAsymmetricEncryptionType(),
|
||||
getKeyDerivationType(), getCipherBlockModeType(), getSymmetricPaddingType(),
|
||||
getAsymmetricPaddingType(), getEllipticCurveType(), getSignatureType(), getKeyExchangeType()
|
||||
]
|
||||
}
|
||||
|
||||
predicate isKnownAlgorithm(string name) { isKnownAlgorithm(name, _) }
|
||||
|
||||
predicate isKnownAlgorithm(string name, string algType) {
|
||||
isHashingAlgorithm(name) and algType = "HASH"
|
||||
or
|
||||
isEncryptionAlgorithm(name, algType) and
|
||||
algType in ["SYMMETRIC_ENCRYPTION", "ASYMMETRIC_ENCRYPTION"]
|
||||
or
|
||||
isKeyDerivationAlgorithm(name) and algType = "KEY_DERIVATION"
|
||||
or
|
||||
isCipherBlockModeAlgorithm(name) and algType = "BLOCK_MODE"
|
||||
or
|
||||
isPaddingAlgorithm(name, algType) and algType in ["SYMMETRIC_PADDING", "ASYMMETRIC_PADDING"]
|
||||
or
|
||||
isEllipticCurveAlgorithm(name) and algType = "ELLIPTIC_CURVE"
|
||||
or
|
||||
isSignatureAlgorithm(name) and algType = "SIGNATURE"
|
||||
or
|
||||
isKeyExchangeAlgorithm(name) and algType = "KEY_EXCHANGE"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` is a known hashing algorithm in the model/library.
|
||||
*/
|
||||
predicate isHashingAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"BLAKE2", "BLAKE2B", "BLAKE2S", "SHA2", "SHA224", "SHA256", "SHA384", "SHA512", "SHA512224",
|
||||
"SHA512256", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", "SHAKE128", "SHAKE256",
|
||||
"SM3", "WHIRLPOOL", "POLY1305", "HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD",
|
||||
"RIPEMD128", "RIPEMD256", "RIPEMD160", "RIPEMD320", "SHA0", "SHA1", "SHA", "MGF1", "MGF1SHA1",
|
||||
"MDC2", "SIPHASH"
|
||||
]
|
||||
}
|
||||
|
||||
predicate isEncryptionAlgorithm(string name, string algType) {
|
||||
isAsymmetricEncryptionAlgorithm(name) and algType = "ASYMMETRIC_ENCRYPTION"
|
||||
or
|
||||
isSymmetricEncryptionAlgorithm(name) and algType = "SYMMETRIC_ENCRYPTION"
|
||||
}
|
||||
|
||||
predicate isEncryptionAlgorithm(string name) { isEncryptionAlgorithm(name, _) }
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a known symmetric encryption algorithm.
|
||||
*/
|
||||
predicate isSymmetricEncryptionAlgorithm(string name) {
|
||||
// NOTE: AES is meant to caputure all possible key lengths
|
||||
name =
|
||||
[
|
||||
"AES", "AES128", "AES192", "AES256", "ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5",
|
||||
"CAMELLIA", "CAMELLIA128", "CAMELLIA192", "CAMELLIA256", "CHACHA", "CHACHA20",
|
||||
"CHACHA20POLY1305", "GOST", "GOSTR34102001", "GOSTR341094", "GOSTR341194", "GOST2814789",
|
||||
"GOSTR341194", "GOST2814789", "GOST28147", "GOSTR341094", "GOST89", "GOST94", "GOST34102012",
|
||||
"GOST34112012", "IDEA", "RABBIT", "SEED", "SM4", "DES", "DESX", "3DES", "TDES", "2DES",
|
||||
"DES3", "TRIPLEDES", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", "ARCFOUR", "ARC5",
|
||||
"RC5", "MAGMA", "KUZNYECHIK"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a known key derivation algorithm.
|
||||
*/
|
||||
predicate isKeyDerivationAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"ARGON2", "CONCATKDF", "CONCATKDFHASH", "CONCATKDFHMAC", "KBKDFCMAC", "BCRYPT", "HKDF",
|
||||
"HKDFEXPAND", "KBKDF", "KBKDFHMAC", "PBKDF1", "PBKDF2", "PBKDF2HMAC", "PKCS5", "SCRYPT",
|
||||
"X963KDF", "EVPKDF"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a known cipher block mode
|
||||
*/
|
||||
predicate isCipherBlockModeAlgorithm(string name) {
|
||||
name = ["CBC", "GCM", "CCM", "CFB", "OFB", "CFB8", "CTR", "OPENPGP", "XTS", "EAX", "SIV", "ECB"]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a known padding algorithm
|
||||
*/
|
||||
predicate isPaddingAlgorithm(string name, string algType) {
|
||||
isSymmetricPaddingAlgorithm(name) and algType = "SYMMETRIC_PADDING"
|
||||
or
|
||||
isAsymmetricPaddingAlgorithm(name) and algType = "ASYMMETRIC_PADDING"
|
||||
}
|
||||
|
||||
/**
|
||||
* holds if `name` corresponds to a known symmetric padding algorithm
|
||||
*/
|
||||
predicate isSymmetricPaddingAlgorithm(string name) { name = ["PKCS7", "ANSIX923"] }
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a known asymmetric padding algorithm
|
||||
*/
|
||||
predicate isAsymmetricPaddingAlgorithm(string name) { name = ["OAEP", "PKCS1V15", "PSS", "KEM"] }
|
||||
|
||||
predicate isBrainpoolCurve(string curveName, int keySize) {
|
||||
// ALL BRAINPOOL CURVES
|
||||
keySize in [160, 192, 224, 256, 320, 384, 512] and
|
||||
(
|
||||
curveName = "BRAINPOOLP" + keySize.toString() + "R1"
|
||||
or
|
||||
curveName = "BRAINPOOLP" + keySize.toString() + "T1"
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSecCurve(string curveName, int keySize) {
|
||||
// ALL SEC CURVES
|
||||
keySize in [112, 113, 128, 131, 160, 163, 192, 193, 224, 233, 239, 256, 283, 384, 409, 521, 571] and
|
||||
exists(string suff | suff in ["R1", "R2", "K1"] |
|
||||
curveName = "SECT" + keySize.toString() + suff or
|
||||
curveName = "SECP" + keySize.toString() + suff
|
||||
)
|
||||
}
|
||||
|
||||
predicate isC2Curve(string curveName, int keySize) {
|
||||
// ALL C2 CURVES
|
||||
keySize in [163, 176, 191, 208, 239, 272, 304, 359, 368, 431] and
|
||||
exists(string pre, string suff |
|
||||
pre in ["PNB", "ONB", "TNB"] and suff in ["V1", "V2", "V3", "V4", "V5", "W1", "R1"]
|
||||
|
|
||||
curveName = "C2" + pre + keySize.toString() + suff
|
||||
)
|
||||
}
|
||||
|
||||
predicate isPrimeCurve(string curveName, int keySize) {
|
||||
// ALL PRIME CURVES
|
||||
keySize in [192, 239, 256] and
|
||||
exists(string suff | suff in ["V1", "V2", "V3"] | curveName = "PRIME" + keySize.toString() + suff)
|
||||
}
|
||||
|
||||
predicate isEllipticCurveAlgorithm(string curveName) { isEllipticCurveAlgorithm(curveName, _) }
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a known elliptic curve.
|
||||
*/
|
||||
predicate isEllipticCurveAlgorithm(string curveName, int keySize) {
|
||||
isSecCurve(curveName, keySize)
|
||||
or
|
||||
isBrainpoolCurve(curveName, keySize)
|
||||
or
|
||||
isC2Curve(curveName, keySize)
|
||||
or
|
||||
isPrimeCurve(curveName, keySize)
|
||||
or
|
||||
curveName = "ES256" and keySize = 256
|
||||
or
|
||||
curveName = "CURVE25519" and keySize = 255
|
||||
or
|
||||
curveName = "X25519" and keySize = 255
|
||||
or
|
||||
curveName = "ED25519" and keySize = 255
|
||||
or
|
||||
curveName = "CURVE448" and keySize = 448 // TODO: need to check the key size
|
||||
or
|
||||
curveName = "ED448" and keySize = 448
|
||||
or
|
||||
curveName = "X448" and keySize = 448
|
||||
or
|
||||
curveName = "NUMSP256T1" and keySize = 256
|
||||
or
|
||||
curveName = "NUMSP384T1" and keySize = 384
|
||||
or
|
||||
curveName = "NUMSP512T1" and keySize = 512
|
||||
or
|
||||
curveName = "SM2" and keySize in [256, 512]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a known signature algorithm.
|
||||
*/
|
||||
predicate isSignatureAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"DSA", "ECDSA", "EDDSA", "ES256", "ES256K", "ES384", "ES512", "ED25519", "ED448", "ECDSA256",
|
||||
"ECDSA384", "ECDSA512"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` is a key exchange algorithm.
|
||||
*/
|
||||
predicate isKeyExchangeAlgorithm(string name) {
|
||||
name = ["ECDH", "DH", "DIFFIEHELLMAN", "X25519", "X448"]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a known asymmetric encryption.
|
||||
*/
|
||||
predicate isAsymmetricEncryptionAlgorithm(string name) { name = ["RSA"] }
|
||||
316
cpp/ql/lib/experimental/cryptography/CryptoArtifact.qll
Normal file
316
cpp/ql/lib/experimental/cryptography/CryptoArtifact.qll
Normal file
@@ -0,0 +1,316 @@
|
||||
import cpp
|
||||
private import experimental.cryptography.CryptoAlgorithmNames
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
|
||||
/*
|
||||
* A cryptographic artifact is a DataFlow::Node associated with some
|
||||
* operation, algorithm, or any other aspect of cryptography.
|
||||
*/
|
||||
|
||||
abstract class CryptographicArtifact extends Expr { }
|
||||
|
||||
// /**
|
||||
// * Associates a symmetric encryption algorithm with a block mode.
|
||||
// * The DataFlow::Node representing this association should be the
|
||||
// * point where the algorithm and block mode are combined.
|
||||
// * This may be at the call to encryption or in the construction
|
||||
// * of an object prior to encryption.
|
||||
// */
|
||||
// abstract class SymmetricCipher extends CryptographicArtifact{
|
||||
// abstract SymmetricEncryptionAlgorithm getEncryptionAlgorithm();
|
||||
// abstract BlockMode getBlockMode();
|
||||
// final predicate hasBlockMode(){
|
||||
// exists(this.getBlockMode())
|
||||
// }
|
||||
// }
|
||||
// /**
|
||||
// * A cryptographic operation is a method call that invokes a cryptographic
|
||||
// * algorithm (encrypt/decrypt) or a function in support of a cryptographic algorithm
|
||||
// * (key generation).
|
||||
// *
|
||||
// * Since operations are related to or in support of algorithms, operations must
|
||||
// * provide a reference to their associated algorithm. Often operataions themselves
|
||||
// * encapsulate algorithms, so operations can also extend CryptographicAlgorithm
|
||||
// * and refer to themselves as the target algorithm.
|
||||
// */
|
||||
// abstract class CryptographicOperation extends CryptographicArtifact, Call{
|
||||
// // bindingset[paramName, ind]
|
||||
// // final DataFlow::Node getParameterSource(int ind, string paramName){
|
||||
// // result = Utils::getUltimateSrcFromApiNode(this.(API::CallNode).getParameter(ind, paramName))
|
||||
// // }
|
||||
// final string getAlgorithmName(){
|
||||
// if exists(this.getAlgorithm().getName())
|
||||
// then result = this.getAlgorithm().getName()
|
||||
// else result = unknownAlgorithm()
|
||||
// }
|
||||
// final predicate hasAlgorithm(){
|
||||
// exists(this.getAlgorithm())
|
||||
// }
|
||||
// final predicate isUnknownAlgorithm(){
|
||||
// this.getAlgorithmName() = unknownAlgorithm()
|
||||
// or
|
||||
// not this.hasAlgorithm()
|
||||
// }
|
||||
// // TODO: this might have to be parameterized by a configuration source for
|
||||
// // situations where an operation is passed an algorithm
|
||||
// abstract CryptographicAlgorithm getAlgorithm();
|
||||
// }
|
||||
// /** A key generation operation for asymmetric keys */
|
||||
// abstract class KeyGen extends CryptographicOperation{
|
||||
// int getAKeySizeInBits(){
|
||||
// result = getKeySizeInBits(_)
|
||||
// }
|
||||
// final predicate hasKeySize(Expr configSrc){
|
||||
// exists(this.getKeySizeInBits(configSrc))
|
||||
// }
|
||||
// final predicate hasKeySize(){
|
||||
// exists(this.getAKeySizeInBits())
|
||||
// }
|
||||
// abstract Expr getKeyConfigSrc();
|
||||
// abstract int getKeySizeInBits(Expr configSrc);
|
||||
// }
|
||||
abstract class CryptographicOperation extends CryptographicArtifact, Call { }
|
||||
|
||||
abstract class KeyGeneration extends CryptographicOperation {
|
||||
// TODO: what if the algorithm is UNKNOWN?
|
||||
abstract Expr getKeyConfigurationSource(CryptographicAlgorithm alg);
|
||||
|
||||
abstract CryptographicAlgorithm getAlgorithm();
|
||||
|
||||
int getKeySizeInBits(CryptographicAlgorithm alg) {
|
||||
result = this.getKeyConfigurationSource(alg).(Literal).getValue().toInt()
|
||||
}
|
||||
|
||||
predicate hasConstantKeySize(CryptographicAlgorithm alg) { exists(this.getKeySizeInBits(alg)) }
|
||||
|
||||
predicate hasKeyConfigurationSource(CryptographicAlgorithm alg) {
|
||||
exists(this.getKeyConfigurationSource(alg))
|
||||
}
|
||||
|
||||
Expr getAKeyConfigurationSource() { result = this.getKeyConfigurationSource(_) }
|
||||
}
|
||||
|
||||
abstract class AsymmetricKeyGeneration extends KeyGeneration { }
|
||||
|
||||
abstract class SymmetricKeyGeneration extends KeyGeneration { }
|
||||
|
||||
/**
|
||||
* A cryptographic algorithm is a `CryptographicArtifact`
|
||||
* representing a cryptographic algorithm (see `CryptoAlgorithmNames.qll`).
|
||||
* Cryptographic algorithms can be functions referencing common crypto algorithms (e.g., hashlib.md5)
|
||||
* or strings that are used in cryptographic operation configurations (e.g., hashlib.new("md5")).
|
||||
* Cryptogrpahic algorithms may also be operations that wrap or abstract one or
|
||||
* more algorithms (e.g., cyrptography.fernet.Fernet and AES, CBC and PKCS7).
|
||||
*
|
||||
* In principle, this class should model the location where an algorithm enters the program, not
|
||||
* necessarily where it is used.
|
||||
*/
|
||||
abstract class CryptographicAlgorithm extends CryptographicArtifact {
|
||||
abstract string getName();
|
||||
|
||||
abstract string getAlgType();
|
||||
|
||||
// string getAlgType(){
|
||||
// if this instanceof HashAlgorithm then result = getHashType()
|
||||
// else if this instanceof KeyDerivationAlgorithm then result = getKeyDerivationType()
|
||||
// else if this instanceof SymmetricEncryptionAlgorithm then result = getSymmetricEncryptionType()
|
||||
// else if this instanceof AsymmetricEncryptionAlgorithm then result = getAsymmetricEncryptionType()
|
||||
// else if this instanceof SymmetricEncryptionAlgorithm then result = getSymmetricPaddingType()
|
||||
// else if this instanceof AsymmetricEncryptionAlgorithm then result = getAsymmetricPaddingType()
|
||||
// else if this instanceof EllipticCurveAlgorithm then result = getEllipticCurveType()
|
||||
// else if this instanceof BlockMode then result = getCipherBlockModeType()
|
||||
// else if this instanceof KeyExchangeAlgorithm then result = getKeyExchangeType()
|
||||
// else if this instanceof SigningAlgorithm then result = getSignatureType()
|
||||
// else result = unknownAlgorithm()
|
||||
// }
|
||||
// TODO: handle case where name isn't known, not just unknown?
|
||||
/**
|
||||
* Normalizes a raw name into a normalized name as found in `CryptoAlgorithmNames.qll`.
|
||||
* Subclassess should override for more api-specific normalization.
|
||||
* By deafult, converts a raw name to upper-case with no hyphen, underscore, hash, or space.
|
||||
*/
|
||||
bindingset[s]
|
||||
string normalizeName(string s) {
|
||||
exists(string normStr | normStr = s.toUpperCase().regexpReplaceAll("[-_ ]|/", "") |
|
||||
result = normStr and isKnownAlgorithm(result)
|
||||
or
|
||||
result = unknownAlgorithm() and not isKnownAlgorithm(normStr)
|
||||
)
|
||||
}
|
||||
|
||||
abstract Expr configurationSink();
|
||||
|
||||
predicate hasConfigurationSink() { exists(this.configurationSink()) }
|
||||
}
|
||||
|
||||
abstract class HashAlgorithm extends CryptographicAlgorithm {
|
||||
final string getHashName() {
|
||||
if exists(string n | n = this.getName() and isHashingAlgorithm(n))
|
||||
then isHashingAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
override string getAlgType() { result = getHashType() }
|
||||
}
|
||||
|
||||
abstract class KeyDerivationAlgorithm extends CryptographicAlgorithm {
|
||||
final string getKDFName() {
|
||||
if exists(string n | n = this.getName() and isKeyDerivationAlgorithm(n))
|
||||
then isKeyDerivationAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
override string getAlgType() { result = getKeyDerivationType() }
|
||||
}
|
||||
|
||||
// abstract class KeyDerivationOperation extends CryptographicOperation{
|
||||
// DataFlow::Node getIterationSizeSrc(){
|
||||
// none()
|
||||
// }
|
||||
// DataFlow::Node getSaltConfigSrc(){
|
||||
// none()
|
||||
// }
|
||||
// DataFlow::Node getHashConfigSrc(){
|
||||
// none()
|
||||
// }
|
||||
// // TODO: get encryption algorithm for CBC-based KDF?
|
||||
// DataFlow::Node getDerivedKeySizeSrc(){
|
||||
// none()
|
||||
// }
|
||||
// DataFlow::Node getModeSrc(){
|
||||
// none()
|
||||
// }
|
||||
// // TODO: add more to cover all the parameters of most KDF operations? Perhaps subclass for each type?
|
||||
// abstract predicate requiresIteration();
|
||||
// abstract predicate requiresSalt();
|
||||
// abstract predicate requiresHash();
|
||||
// //abstract predicate requiresKeySize(); // Going to assume all requires a size
|
||||
// abstract predicate requiresMode();
|
||||
// }
|
||||
abstract class EncryptionAlgorithm extends CryptographicAlgorithm {
|
||||
final predicate isAsymmetric() { this instanceof AsymmetricEncryptionAlgorithm }
|
||||
|
||||
final predicate isSymmetric() { not this.isAsymmetric() }
|
||||
// NOTE: DO_NOT add getEncryptionName here, we rely on the fact the parent
|
||||
// class does not have this common predicate.
|
||||
}
|
||||
|
||||
/**
|
||||
* A parent class to represent any algorithm for which
|
||||
* asymmetric cryptography is involved.
|
||||
* Intended to be distinct from AsymmetricEncryptionAlgorithm
|
||||
* which is intended only for asymmetric algorithms that specifically encrypt.
|
||||
*/
|
||||
abstract class AsymmetricAlgorithm extends CryptographicAlgorithm { }
|
||||
|
||||
/**
|
||||
* Algorithms directly or indirectly related to asymmetric encryption,
|
||||
* e.g., RSA, DSA, but also RSA padding algorithms
|
||||
*/
|
||||
abstract class AsymmetricEncryptionAlgorithm extends AsymmetricAlgorithm, EncryptionAlgorithm {
|
||||
final string getEncryptionName() {
|
||||
if exists(string n | n = this.getName() and isAsymmetricEncryptionAlgorithm(n))
|
||||
then isAsymmetricEncryptionAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
override string getAlgType() { result = getAsymmetricEncryptionType() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Algorithms directly or indirectly related to symmetric encryption,
|
||||
* e.g., AES, DES, but also block modes and padding
|
||||
*/
|
||||
abstract class SymmetricEncryptionAlgorithm extends EncryptionAlgorithm {
|
||||
final string getEncryptionName() {
|
||||
if exists(string n | n = this.getName() and isSymmetricEncryptionAlgorithm(n))
|
||||
then isSymmetricEncryptionAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
// TODO: add a stream cipher predicate?
|
||||
override string getAlgType() { result = getSymmetricEncryptionType() }
|
||||
}
|
||||
|
||||
// Used only to categorize all padding into a single object,
|
||||
// DO_NOT add predicates here. Only for categorization purposes.
|
||||
abstract class PaddingAlgorithm extends CryptographicAlgorithm { }
|
||||
|
||||
abstract class SymmetricPadding extends PaddingAlgorithm {
|
||||
final string getPaddingName() {
|
||||
if exists(string n | n = this.getName() and isSymmetricPaddingAlgorithm(n))
|
||||
then isSymmetricPaddingAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
override string getAlgType() { result = getSymmetricPaddingType() }
|
||||
}
|
||||
|
||||
abstract class AsymmetricPadding extends PaddingAlgorithm {
|
||||
final string getPaddingName() {
|
||||
if exists(string n | n = this.getName() and isAsymmetricPaddingAlgorithm(n))
|
||||
then isAsymmetricPaddingAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
override string getAlgType() { result = getAsymmetricPaddingType() }
|
||||
}
|
||||
|
||||
abstract class EllipticCurveAlgorithm extends AsymmetricAlgorithm {
|
||||
final string getCurveName() {
|
||||
if exists(string n | n = this.getName() and isEllipticCurveAlgorithm(n))
|
||||
then isEllipticCurveAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
final int getCurveBitSize() { isEllipticCurveAlgorithm(this.getCurveName(), result) }
|
||||
|
||||
override string getAlgType() { result = getEllipticCurveType() }
|
||||
}
|
||||
|
||||
abstract class BlockModeAlgorithm extends CryptographicAlgorithm {
|
||||
final string getBlockModeName() {
|
||||
if exists(string n | n = this.getName() and isCipherBlockModeAlgorithm(n))
|
||||
then isCipherBlockModeAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source of the IV configuration.
|
||||
*/
|
||||
abstract Expr getIVorNonce();
|
||||
|
||||
final predicate hasIVorNonce() { exists(this.getIVorNonce()) }
|
||||
|
||||
override string getAlgType() { result = getCipherBlockModeType() }
|
||||
}
|
||||
|
||||
// abstract class KeyWrapOperation extends CryptographicOperation{
|
||||
// }
|
||||
abstract class AuthenticatedEncryptionAlgorithm extends SymmetricEncryptionAlgorithm {
|
||||
final string getAuthticatedEncryptionName() {
|
||||
if exists(string n | n = this.getName() and isSymmetricEncryptionAlgorithm(n))
|
||||
then isSymmetricEncryptionAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class KeyExchangeAlgorithm extends AsymmetricAlgorithm {
|
||||
final string getKeyExchangeName() {
|
||||
if exists(string n | n = this.getName() and isKeyExchangeAlgorithm(n))
|
||||
then isKeyExchangeAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
override string getAlgType() { result = getKeyExchangeType() }
|
||||
}
|
||||
|
||||
abstract class SigningAlgorithm extends AsymmetricAlgorithm {
|
||||
final string getSigningName() {
|
||||
if exists(string n | n = this.getName() and isSignatureAlgorithm(n))
|
||||
then isSignatureAlgorithm(result) and result = this.getName()
|
||||
else result = unknownAlgorithm()
|
||||
}
|
||||
|
||||
override string getAlgType() { result = getSignatureType() }
|
||||
}
|
||||
718
cpp/ql/lib/experimental/cryptography/modules/OpenSSL.qll
Normal file
718
cpp/ql/lib/experimental/cryptography/modules/OpenSSL.qll
Normal file
@@ -0,0 +1,718 @@
|
||||
import cpp
|
||||
import experimental.cryptography.CryptoAlgorithmNames
|
||||
import experimental.cryptography.CryptoArtifact
|
||||
import experimental.cryptography.utils.OpenSSL.CryptoFunction
|
||||
import experimental.cryptography.utils.OpenSSL.AlgorithmSink
|
||||
import experimental.cryptography.utils.OpenSSL.PassthroughFunction
|
||||
import experimental.cryptography.utils.OpenSSL.CryptoAlgorithm
|
||||
import experimental.cryptography.CryptoArtifact
|
||||
// import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* Problematic case in OpenSSL speed.c
|
||||
* static const char *names[ALGOR_NUM] = {
|
||||
* "md2", "mdc2", "md4", "md5", "sha1", "rmd160",
|
||||
* "sha256", "sha512", "whirlpool", "hmac(md5)",
|
||||
* "des-cbc", "des-ede3", "rc4", "idea-cbc", "seed-cbc",
|
||||
* "rc2-cbc", "rc5-cbc", "blowfish", "cast-cbc",
|
||||
* "aes-128-cbc", "aes-192-cbc", "aes-256-cbc",
|
||||
* "camellia-128-cbc", "camellia-192-cbc", "camellia-256-cbc",
|
||||
* "evp", "ghash", "rand", "cmac"
|
||||
* };
|
||||
*
|
||||
* Every entry is considered a block mode, hash, and symmetric encryption algorithm
|
||||
* getEncryptionName for example, will return unknown
|
||||
*/
|
||||
predicate nodeToExpr(DataFlow::Node node, Expr e) {
|
||||
e = node.asExpr() or e = node.asIndirectArgument()
|
||||
}
|
||||
|
||||
Expr getExprFromNode(DataFlow::Node node) { nodeToExpr(node, result) }
|
||||
|
||||
DataFlow::Node getNodeFromExpr(Expr e) { nodeToExpr(result, e) }
|
||||
|
||||
predicate isEVP_PKEY_CTX(Type t) { t.getUnderlyingType().stripType().getName() = "evp_pkey_ctx_st" }
|
||||
|
||||
/**
|
||||
* An expression representing an EVP_PKEY_CTX* at the location of a
|
||||
* known AlgorithmSinkArgument.
|
||||
* The EVP_PKEY_CTX* represents the location where the CTX is tied to the algorithm,
|
||||
* and can be used as a source for tracing EVP_PKEY_CTX to other operations.
|
||||
*/
|
||||
class Known_EVP_PKEY_CTX_Ptr_Source extends Expr {
|
||||
Known_EVP_PKEY_CTX_Ptr_Source() {
|
||||
isEVP_PKEY_CTX(this.getUnderlyingType()) and
|
||||
this.getUnderlyingType() instanceof PointerType and
|
||||
exists(AlgorithmSinkArgument arg, Call sinkCall |
|
||||
arg.getSinkCall() = sinkCall and
|
||||
sinkCall.getAnArgument() = this
|
||||
or
|
||||
this = sinkCall
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// module CTXFlow implements DataFlow::ConfigSig{
|
||||
// predicate isSource(DataFlow::Node source) {
|
||||
// // ASSUMPTION: at a sink, an algorithm is converted into a CTX through a return of the call only
|
||||
// // and is the primary source of interest for CTX tracing
|
||||
// source.asExpr() instanceof AlgorithmSinkArgument
|
||||
// }
|
||||
// predicate isSink(DataFlow::Node sink){
|
||||
// sink.asExpr() instanceof CTXSink
|
||||
// }
|
||||
// predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// // cls.getName() = "asn1_object_st" flow out on any EVP_PKEY_CTX which is "evp_pkey_ctx_st"
|
||||
// exists(Call c |
|
||||
// isEVP_PKEY_CTX(c.getUnderlyingType()) and
|
||||
// node1.asExpr() = c.getAnArgument() and c = node2.asExpr())
|
||||
// }
|
||||
// }
|
||||
// module CTXFlowConfig = DataFlow::Global<CTXFlow>;
|
||||
// TODO: currently only handles tracing from literals to sinks
|
||||
module LiteralAlgorithmTracerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof Literal and
|
||||
// Optimization to reduce literal tracing on integers to only those that are known/relevant NIDs.
|
||||
(
|
||||
exists(source.asExpr().getValue().toInt())
|
||||
implies
|
||||
source.asExpr().getValue().toInt() < getNIDMax()
|
||||
) and
|
||||
// False positives observed inside OBJ_nid2* and OBJ_sn2* functions where NULL is a possible assignment.
|
||||
// While this is a concern, it only occurs if the object being referenced is NULL to begin with
|
||||
// Perhaps a different query should be used to find these caes if they represent a threat.
|
||||
// Filter out any open ssl function source in a function namae Obj_*
|
||||
// False positives in OpenSSL also observed for CRYPTO_strndup (filtering any CRYPTO_* function)
|
||||
// due to setting a null byte in the string
|
||||
(
|
||||
isPossibleOpenSSLFunction(source.getEnclosingCallable())
|
||||
implies
|
||||
(
|
||||
not source.getEnclosingCallable().getName().matches("OBJ_%") and
|
||||
not source.getEnclosingCallable().getName().matches("CRYPTO_%")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
// A sink is a call to a function that takes an algorithm as an argument
|
||||
// must include checks for asIndirectArgument since the input may be a pointer to an object
|
||||
// and the member of the object holds the algorithm on the trace.
|
||||
getExprFromNode(sink) instanceof AlgorithmSinkArgument
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
knownPassThroughStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
// If the node is the 'next' argument of a isCallPassThrough, it is only allowed if it is an out parameter
|
||||
// i.e., a defining argument. This barrier says that if the node is an expression not an out parameter, it is filtered.
|
||||
// Out arguments will not be filtered.
|
||||
exists(Call c | knownPassthoughCall(c, _, node.asExpr()) and c.getAnArgument() = node.asExpr())
|
||||
or
|
||||
// False positive reducer, don't flow out through argv
|
||||
node.asVariable().hasName("argv")
|
||||
or
|
||||
node.asIndirectVariable().hasName("argv")
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
// Assume a read on crypto identifying field for any object of type asn1_object_st (i.e., ASN1_OBJECT)
|
||||
exists(Class cls | cls.getName() = "asn1_object_st" |
|
||||
node.getType().getUnspecifiedType().stripType() = cls and
|
||||
c.(DataFlow::FieldContent).getField() = cls.getAMember() and
|
||||
c.(DataFlow::FieldContent).getField().getName() in ["nid", "sn", "ln"]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module LiteralAlgorithmTracer = DataFlow::Global<LiteralAlgorithmTracerConfig>;
|
||||
|
||||
/**
|
||||
* `source` is an expression that is a source of an algorithm of type `algType`.
|
||||
* `algType` may be `UNKONWN`.
|
||||
* See CryptoAlgorithmNames for other possible values of `algType`.
|
||||
*/
|
||||
bindingset[sinkAlgType]
|
||||
predicate hasLiteralPathToAlgSink(DataFlow::Node source, DataFlow::Node sink, string sinkAlgType) {
|
||||
LiteralAlgorithmTracer::flow(source, sink) and
|
||||
getExprFromNode(sink).(AlgorithmSinkArgument).algType() = sinkAlgType
|
||||
}
|
||||
|
||||
private predicate knownTracedAlgorithm(Literal e, string srcSinkType) {
|
||||
knownTracedAlgorithm(e, srcSinkType, srcSinkType)
|
||||
}
|
||||
|
||||
private predicate knownTracedAlgorithm(Literal e, string srcType, string sinkType) {
|
||||
resolveAlgorithmFromLiteral(e, _, srcType) and
|
||||
hasLiteralPathToAlgSink(DataFlow::exprNode(e), _, sinkType) and
|
||||
isKnownType(sinkType) and
|
||||
isKnownType(srcType)
|
||||
}
|
||||
|
||||
private predicate unknownTracedLiteralAlgorithm(Literal e, string srcSinkType) {
|
||||
// Asymmetric special case:
|
||||
// Since asymmetric algorithm sinks are used for various categories of asymmetric algorithms
|
||||
// an asymmetric algorithm is only unknown if there is no trace from any asymmetric type to the given srcSinkType sink
|
||||
if getAsymmetricType() = srcSinkType
|
||||
then forall(string t | t = getAsymmetricType() | unknownTracedLiteralAlgorithm(e, t, srcSinkType))
|
||||
else unknownTracedLiteralAlgorithm(e, srcSinkType, srcSinkType)
|
||||
}
|
||||
|
||||
private predicate unknownTracedLiteralAlgorithm(Literal e, string srcType, string sinkType) {
|
||||
// the literal resolves to an algorithm, but not to the sinktype
|
||||
// or generally doesn't resolve to any algorithm type
|
||||
// this case covers 'nonsense' cases e.g., use RSA for symmetric encryption
|
||||
not resolveAlgorithmFromLiteral(e, _, srcType) and
|
||||
isValidAlgorithmLiteral(e) and
|
||||
hasLiteralPathToAlgSink(DataFlow::exprNode(e), _, sinkType) and
|
||||
isKnownType(sinkType) and
|
||||
isKnownType(srcType)
|
||||
}
|
||||
|
||||
private predicate unknownTracedNonLiteralAlgorithm(AlgorithmSinkArgument e, string srcSinkType) {
|
||||
// Asymmetric special case:
|
||||
// Since asymmetric algorithm sinks are used for various categories of asymmetric algorithms
|
||||
// an asymmetric algorithm is only unknown if there is no trace from any asymmetric type to the given srcSinkType sink
|
||||
if getAsymmetricType() = srcSinkType
|
||||
then
|
||||
forall(string t | t = getAsymmetricType() | unknownTracedNonLiteralAlgorithm(e, t, srcSinkType))
|
||||
else unknownTracedNonLiteralAlgorithm(e, srcSinkType, srcSinkType)
|
||||
}
|
||||
|
||||
private predicate unknownTracedNonLiteralAlgorithm(
|
||||
AlgorithmSinkArgument e, string srcType, string sinkType
|
||||
) {
|
||||
not hasLiteralPathToAlgSink(_, getNodeFromExpr(e), srcType) and
|
||||
LiteralAlgorithmTracerConfig::isSink(getNodeFromExpr(e)) and
|
||||
e.algType() = sinkType and
|
||||
isKnownType(srcType) and
|
||||
isKnownType(sinkType)
|
||||
}
|
||||
|
||||
private predicate functionAlgorithm(Call c, string algType) {
|
||||
isOpenSSLCryptoFunctionCall(c, _, algType)
|
||||
}
|
||||
|
||||
abstract class OpenSSLTracedAlgorithm extends CryptographicAlgorithm {
|
||||
override string getName() { resolveAlgorithmFromLiteral(this, result, this.getAlgType()) }
|
||||
|
||||
override Expr configurationSink() {
|
||||
exists(DataFlow::Node sink |
|
||||
hasLiteralPathToAlgSink(DataFlow::exprNode(this), sink, this.getAlgType())
|
||||
|
|
||||
result = getExprFromNode(sink)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class OpenSSLFunctionAlgorithm extends CryptographicAlgorithm {
|
||||
override string getName() { isOpenSSLCryptoFunctionCall(this, result, this.getAlgType()) }
|
||||
|
||||
override Expr configurationSink() { result = this }
|
||||
}
|
||||
|
||||
abstract class OpenSSLUnknownTracedLiteralAlgorithm extends CryptographicAlgorithm {
|
||||
override string getName() { result = unknownAlgorithm() }
|
||||
|
||||
override Expr configurationSink() {
|
||||
exists(DataFlow::Node sink |
|
||||
hasLiteralPathToAlgSink(DataFlow::exprNode(this), sink, this.getAlgType())
|
||||
|
|
||||
result = getExprFromNode(sink)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class OpenSSLUnknownTracedNonLiteralAlgorithm extends CryptographicAlgorithm {
|
||||
override string getName() { result = unknownAlgorithm() }
|
||||
|
||||
override Expr configurationSink() { result = this }
|
||||
}
|
||||
|
||||
module SymmetricEncryption {
|
||||
abstract class OpenSSLSymmetricEncryptionAlgorithm extends SymmetricEncryptionAlgorithm { }
|
||||
|
||||
class OpenSSLSymmetricEncryptionTracedAlgorithm extends OpenSSLTracedAlgorithm,
|
||||
OpenSSLSymmetricEncryptionAlgorithm
|
||||
{
|
||||
OpenSSLSymmetricEncryptionTracedAlgorithm() {
|
||||
knownTracedAlgorithm(this, getSymmetricEncryptionType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLSymmetricEncryptionFunctionAlgorithm extends OpenSSLFunctionAlgorithm,
|
||||
OpenSSLSymmetricEncryptionAlgorithm
|
||||
{
|
||||
OpenSSLSymmetricEncryptionFunctionAlgorithm() {
|
||||
functionAlgorithm(this, getSymmetricEncryptionType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLSymmetricEncryptionTracedUnknownLiteralAlgorithm extends OpenSSLUnknownTracedLiteralAlgorithm,
|
||||
OpenSSLSymmetricEncryptionAlgorithm
|
||||
{
|
||||
OpenSSLSymmetricEncryptionTracedUnknownLiteralAlgorithm() {
|
||||
unknownTracedLiteralAlgorithm(this, getSymmetricEncryptionType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLSymmetricEncryptionUnknownNonLiteralTracedAlgorithm extends OpenSSLUnknownTracedNonLiteralAlgorithm,
|
||||
OpenSSLSymmetricEncryptionAlgorithm
|
||||
{
|
||||
OpenSSLSymmetricEncryptionUnknownNonLiteralTracedAlgorithm() {
|
||||
unknownTracedNonLiteralAlgorithm(this, getSymmetricEncryptionType())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module BlockModes {
|
||||
/**
|
||||
* In OpenSSL, block modes are associated directly with symmetric encryption algorithms.
|
||||
* As such, OpenSSLBLockModes are modeled as extensions of any openssl symmetric encryption algorithm
|
||||
*/
|
||||
class OpenSSLBlockModeAlgorithm extends BlockModeAlgorithm, Expr instanceof SymmetricEncryption::OpenSSLSymmetricEncryptionAlgorithm
|
||||
{
|
||||
OpenSSLBlockModeAlgorithm() {
|
||||
//two cases, either the block mode is a literal or it is a function call
|
||||
resolveAlgorithmFromLiteral(this, _, "BLOCK_MODE")
|
||||
or
|
||||
isOpenSSLCryptoFunctionCall(this, _, "BLOCK_MODE")
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
resolveAlgorithmFromLiteral(this, result, "BLOCK_MODE")
|
||||
or
|
||||
isOpenSSLCryptoFunctionCall(this, result, "BLOCK_MODE")
|
||||
}
|
||||
|
||||
override Expr configurationSink() {
|
||||
result = this.(SymmetricEncryption::OpenSSLSymmetricEncryptionAlgorithm).configurationSink()
|
||||
}
|
||||
|
||||
override Expr getIVorNonce() {
|
||||
// TODO
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class UnknownOpenSSLBlockModeAlgorithm extends BlockModeAlgorithm, Expr instanceof SymmetricEncryption::OpenSSLSymmetricEncryptionAlgorithm
|
||||
{
|
||||
UnknownOpenSSLBlockModeAlgorithm() {
|
||||
//two cases, either the block mode is a literal or it is a function call
|
||||
not resolveAlgorithmFromLiteral(this, _, "BLOCK_MODE") and
|
||||
not isOpenSSLCryptoFunctionCall(this, _, "BLOCK_MODE")
|
||||
}
|
||||
|
||||
override string getName() { result = unknownAlgorithm() }
|
||||
|
||||
override Expr configurationSink() {
|
||||
result = this.(SymmetricEncryption::OpenSSLSymmetricEncryptionAlgorithm).configurationSink()
|
||||
}
|
||||
|
||||
override Expr getIVorNonce() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module Hashes {
|
||||
abstract class OpenSSLHashAlgorithm extends HashAlgorithm { }
|
||||
|
||||
class OpenSSLHashTracedAlgorithm extends OpenSSLTracedAlgorithm, OpenSSLHashAlgorithm {
|
||||
OpenSSLHashTracedAlgorithm() { knownTracedAlgorithm(this, getHashType()) }
|
||||
}
|
||||
|
||||
class OpenSSLHashFunctionAlgorithm extends OpenSSLFunctionAlgorithm, OpenSSLHashAlgorithm {
|
||||
OpenSSLHashFunctionAlgorithm() { functionAlgorithm(this, getHashType()) }
|
||||
}
|
||||
|
||||
class OpenSSLHashTracedUnknownLiteralAlgorithm extends OpenSSLUnknownTracedLiteralAlgorithm,
|
||||
OpenSSLHashAlgorithm
|
||||
{
|
||||
OpenSSLHashTracedUnknownLiteralAlgorithm() {
|
||||
unknownTracedLiteralAlgorithm(this, getHashType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLHashUnknownNonLiteralTracedAlgorithm extends OpenSSLUnknownTracedNonLiteralAlgorithm,
|
||||
OpenSSLHashAlgorithm
|
||||
{
|
||||
OpenSSLHashUnknownNonLiteralTracedAlgorithm() {
|
||||
unknownTracedNonLiteralAlgorithm(this, getHashType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLNullHash extends HashAlgorithm {
|
||||
OpenSSLNullHash() {
|
||||
exists(Call c |
|
||||
this = c and
|
||||
isPossibleOpenSSLFunction(c.getTarget()) and
|
||||
c.getTarget().getName() in ["EVP_md_null"]
|
||||
)
|
||||
}
|
||||
|
||||
override string getName() { result = unknownAlgorithm() }
|
||||
|
||||
override Expr configurationSink() { result = this }
|
||||
}
|
||||
}
|
||||
|
||||
module EllipticCurves {
|
||||
// TODO: need to address EVP_PKEY_Q_keygen where the type is "EC" but the curve is UNKNOWN?
|
||||
class OpenSSLEllipticCurveTracedAlgorithm extends OpenSSLTracedAlgorithm, EllipticCurveAlgorithm {
|
||||
OpenSSLEllipticCurveTracedAlgorithm() { knownTracedAlgorithm(this, getEllipticCurveType()) }
|
||||
}
|
||||
|
||||
class OpenSSLEllipticCurveFunctionAlgorithm extends OpenSSLFunctionAlgorithm,
|
||||
EllipticCurveAlgorithm
|
||||
{
|
||||
OpenSSLEllipticCurveFunctionAlgorithm() { functionAlgorithm(this, getEllipticCurveType()) }
|
||||
}
|
||||
|
||||
class OpenSSLEllipticCurveTracedUnknownLiteralAlgorithm extends OpenSSLUnknownTracedLiteralAlgorithm,
|
||||
EllipticCurveAlgorithm
|
||||
{
|
||||
OpenSSLEllipticCurveTracedUnknownLiteralAlgorithm() {
|
||||
unknownTracedLiteralAlgorithm(this, getEllipticCurveType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLEllipticCurvehUnknownNonLiteralTracedAlgorithm extends OpenSSLUnknownTracedNonLiteralAlgorithm,
|
||||
EllipticCurveAlgorithm
|
||||
{
|
||||
OpenSSLEllipticCurvehUnknownNonLiteralTracedAlgorithm() {
|
||||
unknownTracedNonLiteralAlgorithm(this, getEllipticCurveType())
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EC_KEY_new_ex.html
|
||||
class OpenSSLNullEllipticCurve extends EllipticCurveAlgorithm {
|
||||
OpenSSLNullEllipticCurve() {
|
||||
exists(Call c |
|
||||
this = c and
|
||||
isPossibleOpenSSLFunction(c.getTarget()) and
|
||||
c.getTarget().getName() in ["EC_KEY_new", "EC_KEY_new_ex"]
|
||||
)
|
||||
}
|
||||
|
||||
override string getName() { result = unknownAlgorithm() }
|
||||
|
||||
override Expr configurationSink() { result = this }
|
||||
}
|
||||
}
|
||||
|
||||
module AsymmetricEncryption {
|
||||
class OpenSSLAsymmetricEncryptionTracedAlgorithm extends OpenSSLTracedAlgorithm,
|
||||
AsymmetricEncryptionAlgorithm
|
||||
{
|
||||
OpenSSLAsymmetricEncryptionTracedAlgorithm() {
|
||||
knownTracedAlgorithm(this, getAsymmetricEncryptionType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLAsymmetricEncryptionFunctionAlgorithm extends OpenSSLFunctionAlgorithm,
|
||||
AsymmetricEncryptionAlgorithm
|
||||
{
|
||||
OpenSSLAsymmetricEncryptionFunctionAlgorithm() {
|
||||
functionAlgorithm(this, getAsymmetricEncryptionType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLAsymmetricEncryptionTracedUnknownLiteralAlgorithm extends OpenSSLUnknownTracedLiteralAlgorithm,
|
||||
AsymmetricEncryptionAlgorithm
|
||||
{
|
||||
OpenSSLAsymmetricEncryptionTracedUnknownLiteralAlgorithm() {
|
||||
unknownTracedLiteralAlgorithm(this, getAsymmetricEncryptionType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLAsymmetricEncryptionUnknownNonLiteralTracedAlgorithm extends OpenSSLUnknownTracedNonLiteralAlgorithm,
|
||||
AsymmetricEncryptionAlgorithm
|
||||
{
|
||||
OpenSSLAsymmetricEncryptionUnknownNonLiteralTracedAlgorithm() {
|
||||
unknownTracedNonLiteralAlgorithm(this, getAsymmetricEncryptionType())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module SigningAlgorithms {
|
||||
class OpenSSLSignatureTracedAlgorithm extends OpenSSLTracedAlgorithm, SigningAlgorithm {
|
||||
OpenSSLSignatureTracedAlgorithm() { knownTracedAlgorithm(this, getSignatureType()) }
|
||||
}
|
||||
|
||||
class OpenSSLSignatureFunctionAlgorithm extends OpenSSLFunctionAlgorithm, SigningAlgorithm {
|
||||
OpenSSLSignatureFunctionAlgorithm() { functionAlgorithm(this, getSignatureType()) }
|
||||
}
|
||||
|
||||
class OpenSSLSignatureTracedUnknownLiteralAlgorithm extends OpenSSLUnknownTracedLiteralAlgorithm,
|
||||
SigningAlgorithm
|
||||
{
|
||||
OpenSSLSignatureTracedUnknownLiteralAlgorithm() {
|
||||
unknownTracedLiteralAlgorithm(this, getSignatureType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLSignatureUnknownNonLiteralTracedAlgorithm extends OpenSSLUnknownTracedNonLiteralAlgorithm,
|
||||
SigningAlgorithm
|
||||
{
|
||||
OpenSSLSignatureUnknownNonLiteralTracedAlgorithm() {
|
||||
unknownTracedNonLiteralAlgorithm(this, getSignatureType())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module KeyExchange {
|
||||
class OpenSSLKeyExchangeTracedAlgorithm extends OpenSSLTracedAlgorithm, KeyExchangeAlgorithm {
|
||||
OpenSSLKeyExchangeTracedAlgorithm() { knownTracedAlgorithm(this, getKeyExchangeType()) }
|
||||
}
|
||||
|
||||
class OpenSSLKeyExchangeFunctionAlgorithm extends OpenSSLFunctionAlgorithm, KeyExchangeAlgorithm {
|
||||
OpenSSLKeyExchangeFunctionAlgorithm() { functionAlgorithm(this, getKeyExchangeType()) }
|
||||
}
|
||||
|
||||
class OpenSSLKeyExchangeTracedUnknownLiteralAlgorithm extends OpenSSLUnknownTracedLiteralAlgorithm,
|
||||
KeyExchangeAlgorithm
|
||||
{
|
||||
OpenSSLKeyExchangeTracedUnknownLiteralAlgorithm() {
|
||||
unknownTracedLiteralAlgorithm(this, getKeyExchangeType())
|
||||
}
|
||||
}
|
||||
|
||||
class OpenSSLKeyExchangeUnknownNonLiteralTracedAlgorithm extends OpenSSLUnknownTracedNonLiteralAlgorithm,
|
||||
KeyExchangeAlgorithm
|
||||
{
|
||||
OpenSSLKeyExchangeUnknownNonLiteralTracedAlgorithm() {
|
||||
unknownTracedNonLiteralAlgorithm(this, getKeyExchangeType())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module KeyGeneration {
|
||||
/**
|
||||
* Functions that explicitly set key generation parameters.
|
||||
* `sizeInd` is the parameter specifying the size of the key.
|
||||
* `outInd` is the parameter or return value that the key is written to.
|
||||
* `outInd` is -1 if the key is written to the return value.
|
||||
*/
|
||||
predicate isAsymmetricKeyGenExplicitAlgorithm(Function func, int sizeInd, int outInd) {
|
||||
isPossibleOpenSSLFunction(func) and
|
||||
exists(string name | func.hasGlobalName(name) |
|
||||
name in [
|
||||
"EVP_PKEY_CTX_set_dsa_paramgen_bits", "DSA_generate_parameters_ex",
|
||||
"EVP_PKEY_CTX_set_rsa_keygen_bits", "RSA_generate_key_ex", "RSA_generate_key_fips",
|
||||
"EVP_PKEY_CTX_set_dh_paramgen_prime_len", "DH_generate_parameters_ex"
|
||||
] and
|
||||
sizeInd = 1 and
|
||||
outInd = 0
|
||||
or
|
||||
name in ["DSA_generate_parameters", "RSA_generate_key", "DH_generate_parameters"] and
|
||||
sizeInd = 0 and
|
||||
outInd = -1
|
||||
) and
|
||||
exists(Type t |
|
||||
(
|
||||
if sizeInd = -1
|
||||
then t = func.getType().getUnderlyingType()
|
||||
else t = func.getParameter(sizeInd).getUnderlyingType()
|
||||
) and
|
||||
t instanceof IntegralType and
|
||||
not t instanceof CharType
|
||||
)
|
||||
}
|
||||
|
||||
module AsymExplicitAlgKeyLengthFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
// Optimizations to avoid tracing all integers
|
||||
node.asExpr().(Literal).getValue().toInt() > 0 and // exclude sentinel values
|
||||
node.asExpr().(Literal).getValue().toInt() < 8500
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(FunctionCall c, int sizeInd |
|
||||
isAsymmetricKeyGenExplicitAlgorithm(c.getTarget(), sizeInd, _) and
|
||||
c.getArgument(sizeInd) = node.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module AsymExplicitAlgKeyLengthFlow = DataFlow::Global<AsymExplicitAlgKeyLengthFlowConfig>;
|
||||
|
||||
class OpenSSLAsymmetricKeyGenTiedToAlgorithm extends AsymmetricKeyGeneration {
|
||||
OpenSSLAsymmetricKeyGenTiedToAlgorithm() {
|
||||
exists(Call c |
|
||||
this = c and
|
||||
isPossibleOpenSSLFunction(c.getTarget()) and
|
||||
isAsymmetricKeyGenExplicitAlgorithm(c.getTarget(), _, _)
|
||||
)
|
||||
}
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = this }
|
||||
|
||||
override Expr getKeyConfigurationSource(CryptographicAlgorithm alg) {
|
||||
alg = this and
|
||||
exists(int sizeInd |
|
||||
isAsymmetricKeyGenExplicitAlgorithm(this.getTarget(), sizeInd, _) and
|
||||
AsymExplicitAlgKeyLengthFlow::flow(DataFlow::exprNode(result),
|
||||
DataFlow::exprNode(this.getArgument(sizeInd)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module Length_to_RSA_EVP_PKEY_Q_keygen_Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
// Optimizations to avoid tracing all integers
|
||||
node.asExpr().(Literal).getValue().toInt() > 0 and // exclude sentinel values
|
||||
node.asExpr().(Literal).getValue().toInt() < 5000
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(FunctionCall c |
|
||||
c.getTarget().getName() = "EVP_PKEY_Q_keygen" and
|
||||
isPossibleOpenSSLFunction(c.getTarget()) and
|
||||
c.getArgument(3) = node.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module Length_to_RSA_EVP_PKEY_Q_keygen_Flow =
|
||||
DataFlow::Global<Length_to_RSA_EVP_PKEY_Q_keygen_Config>;
|
||||
|
||||
class OpenSSL_RSA_EVP_PKEY_Q_keygen extends AsymmetricKeyGeneration {
|
||||
OpenSSL_RSA_EVP_PKEY_Q_keygen() {
|
||||
exists(Call c |
|
||||
this = c and
|
||||
isPossibleOpenSSLFunction(c.getTarget()) and
|
||||
this.getTarget().getName() = "EVP_PKEY_Q_keygen" and
|
||||
this.getArgument(3).getUnderlyingType() instanceof IntegralType
|
||||
)
|
||||
}
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() {
|
||||
result.configurationSink().(AlgorithmSinkArgument).getSinkCall() = this
|
||||
}
|
||||
|
||||
override Expr getKeyConfigurationSource(CryptographicAlgorithm alg) {
|
||||
alg = this.getAlgorithm() and
|
||||
Length_to_RSA_EVP_PKEY_Q_keygen_Flow::flow(DataFlow::exprNode(result),
|
||||
DataFlow::exprNode(this.getArgument(3)))
|
||||
}
|
||||
}
|
||||
|
||||
predicate isKeyGenOperationWithNoSize(Function func) {
|
||||
isPossibleOpenSSLFunction(func) and
|
||||
exists(string name | func.hasGlobalName(name) |
|
||||
name in ["EVP_PKEY_keygen", "DSA_generate_key", "DH_generate_key", "EVP_PKEY_generate"]
|
||||
)
|
||||
}
|
||||
|
||||
module KeyGenKeySizeInitToKeyGenConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
exists(Call c, Function func, int outInd |
|
||||
isAsymmetricKeyGenExplicitAlgorithm(func, _, outInd) and
|
||||
c.getTarget() = func
|
||||
|
|
||||
if outInd = -1 then node.asExpr() = c else node.asExpr() = c.getArgument(outInd)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(Call c |
|
||||
isKeyGenOperationWithNoSize(c.getTarget()) and c.getAnArgument() = node.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module KeyGenKeySizeInitToKeyGenFlow = DataFlow::Global<KeyGenKeySizeInitToKeyGenConfig>;
|
||||
|
||||
predicate isEVP_PKEY_CTX_Source(DataFlow::Node node, CryptographicAlgorithm alg) {
|
||||
exists(Call c |
|
||||
alg.configurationSink().(AlgorithmSinkArgument).getSinkCall() = c and
|
||||
(
|
||||
node.asExpr() = c
|
||||
or
|
||||
node.asExpr() = c.getAnArgument()
|
||||
or
|
||||
node.asDefiningArgument() = c.getAnArgument()
|
||||
)
|
||||
) and
|
||||
(
|
||||
node.asExpr() instanceof Known_EVP_PKEY_CTX_Ptr_Source
|
||||
or
|
||||
node.asDefiningArgument() instanceof Known_EVP_PKEY_CTX_Ptr_Source
|
||||
)
|
||||
}
|
||||
|
||||
predicate isKeyGen_EVP_PKEY_CTX_Sink(DataFlow::Node node, Call c) {
|
||||
isKeyGenOperationWithNoSize(c.getTarget()) and nodeToExpr(node, c.getAnArgument())
|
||||
}
|
||||
|
||||
/**
|
||||
* Trace from EVP_PKEY_CTX* at algorithm sink to keygen,
|
||||
* users can then extrapolatae the matching algorithm from the alg sink to the keygen
|
||||
*/
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isEVP_PKEY_CTX_Source(source, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isKeyGen_EVP_PKEY_CTX_Sink(sink, _) }
|
||||
}
|
||||
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize_Flow =
|
||||
DataFlow::Global<EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize>;
|
||||
|
||||
/**
|
||||
* UNKNOWN key sizes to general purpose key generation functions (i.e., that take in no key size and assume
|
||||
* is it set on context prior to the call). No path from a key configuration to these operations
|
||||
* means the key size is UNKNOWN, or more precisely the key size is DEFAULT but
|
||||
* the defaults can change with each version of OpenSSL, we simply assume the size is generally UNKNOWN.
|
||||
* ASSUMPTION/TODO: we currently model all known locations where a key size is set explicitly.
|
||||
* When a key is set implicitly, this usually means a key generation operation
|
||||
* is called where the operation takes in no key size, and no flow to this operation
|
||||
* initializes the context with a key size.
|
||||
* Currently, without a definitive source (set of sources) to start tracing from, we cannot determine
|
||||
* determine if a single path exists that initializes the context with a key size and another that doesn't.
|
||||
* Rather than attempt to model all possible sources, we assume that if no path
|
||||
* from a key config location reaches a generic key generation operation, then the key size is not set.
|
||||
* NOTE: while this is true, it is possible a key size is set in one path, but not in another
|
||||
* meaning this approach (and other similar approaches used in this model for UNKNOWN)
|
||||
* can produce false negatives.
|
||||
*/
|
||||
class OpenSSLDefaultKeyGeneration extends AsymmetricKeyGeneration {
|
||||
OpenSSLDefaultKeyGeneration() {
|
||||
// this is a call to a function matching isKeyGenOperationWithNoSize
|
||||
// and there is no flow from a key configuration source to this call
|
||||
exists(Call c |
|
||||
this = c and
|
||||
isKeyGenOperationWithNoSize(this.getTarget()) and
|
||||
not exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
KeyGenKeySizeInitToKeyGenFlow::flow(src, sink) and
|
||||
nodeToExpr(sink, this.getAnArgument())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() {
|
||||
if this.getTarget().getName() in ["DSA_generate_key", "DH_generate_key"]
|
||||
then result = this
|
||||
else
|
||||
// NOTE/ASSUMPTION: EVP_PKEY_keygen, EVP_PKEY_generate assume only other possibilities,
|
||||
// each take in a CTX as the first arg, need to trace from an alg sink from this CTX param
|
||||
// get every alg sink, get the corresponding call, trace out on any CTX type variable
|
||||
// to the key gen
|
||||
// NOTE: looking for any cryptographic algorithm tracing to the keygen to handle
|
||||
// any odd cases we aren't awaare of where keygen can be used for other algorithm types
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize_Flow::flow(src, sink) and
|
||||
isEVP_PKEY_CTX_Source(src, result) and
|
||||
isKeyGen_EVP_PKEY_CTX_Sink(sink, this)
|
||||
// TODO: what if there is no CTX source? then the keygen becomes an UNKNOWN sink
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* For this class, there is no known configuration source for any algorithm
|
||||
*/
|
||||
override Expr getKeyConfigurationSource(CryptographicAlgorithm alg) { none() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
/**
|
||||
* Predicates/classes for identifying algorithm sinks.
|
||||
* An Algorithm Sink is a function that takes an algorithm as an argument.
|
||||
* In particular, any function that takes in an algorithm that until the call
|
||||
* the algorithm is not definitely known to be an algorithm (e.g., an integer used as an identifier to fetch an algorithm)
|
||||
*/
|
||||
|
||||
//TODO: enforce a hierarchy of AlgorithmSinkArgument, e.g., so I can get all Asymmetric SinkArguments that includes all the strictly RSA etc.
|
||||
import cpp
|
||||
import experimental.cryptography.utils.OpenSSL.LibraryFunction
|
||||
import experimental.cryptography.CryptoAlgorithmNames
|
||||
|
||||
predicate isAlgorithmSink(AlgorithmSinkArgument arg, string algType) { arg.algType() = algType }
|
||||
|
||||
abstract class AlgorithmSinkArgument extends Expr {
|
||||
AlgorithmSinkArgument() {
|
||||
exists(Call c | c.getAnArgument() = this and openSSLLibraryFunc(c.getTarget()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function call in which the argument exists
|
||||
*/
|
||||
Call getSinkCall() { result.getAnArgument() = this }
|
||||
|
||||
abstract string algType();
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_fetch.html
|
||||
predicate cipherAlgorithmSink(string funcName, int argInd) {
|
||||
funcName in ["EVP_get_cipherbyname", "EVP_get_cipherbynid", "EVP_get_cipherbyobj"] and argInd = 0
|
||||
or
|
||||
funcName = "EVP_CIPHER_fetch" and argInd = 1
|
||||
}
|
||||
|
||||
class CipherAlgorithmSink extends AlgorithmSinkArgument {
|
||||
CipherAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
cipherAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = getSymmetricEncryptionType() }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_MAC_fetch
|
||||
predicate macAlgorithmSink(string funcName, int argInd) {
|
||||
(funcName = "EVP_MAC_fetch" and argInd = 1)
|
||||
}
|
||||
|
||||
class MACAlgorithmSink extends AlgorithmSinkArgument {
|
||||
MACAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
macAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = "TBD" }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_MD_fetch
|
||||
predicate messageDigestAlgorithmSink(string funcName, int argInd) {
|
||||
funcName in ["EVP_get_digestbyname", "EVP_get_digestbynid", "EVP_get_digestbyobj"] and argInd = 0
|
||||
or
|
||||
funcName = "EVP_MD_fetch" and argInd = 1
|
||||
}
|
||||
|
||||
class MessageDigestAlgorithmSink extends AlgorithmSinkArgument {
|
||||
MessageDigestAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
messageDigestAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = getHashType() }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_KEYEXCH_fetch
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_KEM_fetch
|
||||
predicate keyExchangeAlgorithmSink(string funcName, int argInd) {
|
||||
funcName = "EVP_KEYEXCH_fetch" and argInd = 1
|
||||
or
|
||||
funcName = "EVP_KEM_fetch" and argInd = 1
|
||||
}
|
||||
|
||||
class KeyExchangeAlgorithmSink extends AlgorithmSinkArgument {
|
||||
KeyExchangeAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
keyExchangeAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = getKeyExchangeType() }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_KEYMGMT_fetch
|
||||
predicate keyManagementAlgorithmSink(string funcName, int argInd) {
|
||||
funcName = "EVP_KEYMGMT_fetch" and argInd = 1
|
||||
}
|
||||
|
||||
class KeyManagementAlgorithmSink extends AlgorithmSinkArgument {
|
||||
KeyManagementAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
keyManagementAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = "TBD" }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_KDF
|
||||
predicate keyDerivationAlgorithmSink(string funcName, int argInd) {
|
||||
funcName = "EVP_KDF_fetch" and argInd = 1
|
||||
}
|
||||
|
||||
class KeyDerivationAlgorithmSink extends AlgorithmSinkArgument {
|
||||
KeyDerivationAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
keyDerivationAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = getKeyDerivationType() }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_ASYM_CIPHER_fetch
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_new_id
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_new_CMAC_key.html
|
||||
predicate asymmetricCipherAlgorithmSink(string funcName, int argInd) {
|
||||
funcName = "EVP_ASYM_CIPHER_fetch" and argInd = 1
|
||||
or
|
||||
funcName = "EVP_PKEY_new_CMAC_key" and argInd = 3
|
||||
// NOTE: other cases are handled by AsymmetricAlgorithmSink
|
||||
}
|
||||
|
||||
class AsymmetricCipherAlgorithmSink extends AlgorithmSinkArgument {
|
||||
AsymmetricCipherAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
asymmetricCipherAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = "ASYMMETRIC_ENCRYPTION" }
|
||||
}
|
||||
|
||||
class AsymmetricCipherAlgorithmSink_EVP_PKEY_Q_keygen extends AlgorithmSinkArgument {
|
||||
AsymmetricCipherAlgorithmSink_EVP_PKEY_Q_keygen() {
|
||||
exists(Call c, string funcName |
|
||||
funcName = c.getTarget().getName() and
|
||||
this = c.getArgument(3)
|
||||
|
|
||||
funcName = "EVP_PKEY_Q_keygen" and
|
||||
c.getArgument(3).getType().getUnderlyingType() instanceof IntegralType
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = "ASYMMETRIC_ENCRYPTION" }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_RAND_fetch
|
||||
predicate randomAlgorithmSink(string funcName, int argInd) {
|
||||
funcName = "EVP_RAND_fetch" and argInd = 1
|
||||
}
|
||||
|
||||
class RandomAlgorithmSink extends AlgorithmSinkArgument {
|
||||
RandomAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
randomAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = "TBD" }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_SIGNATURE_fetch
|
||||
predicate signatureAlgorithmSink(string funcName, int argInd) {
|
||||
funcName = "EVP_SIGNATURE_fetch" and argInd = 1
|
||||
}
|
||||
|
||||
class SignatureAlgorithmSink extends AlgorithmSinkArgument {
|
||||
SignatureAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
signatureAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = getSignatureType() }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EC_KEY_new_by_curve_name.html
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_ec_paramgen_curve_nid.html
|
||||
predicate ellipticCurveAlgorithmSink(string funcName, int argInd) {
|
||||
funcName in ["EC_KEY_new_by_curve_name", "EVP_EC_gen"] and argInd = 0
|
||||
or
|
||||
funcName = "EC_KEY_new_by_curve_name_ex" and argInd = 2
|
||||
or
|
||||
funcName in ["EVP_PKEY_CTX_set_ec_paramgen_curve_nid"] and argInd = 1
|
||||
}
|
||||
|
||||
class EllipticCurveAlgorithmSink extends AlgorithmSinkArgument {
|
||||
EllipticCurveAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
ellipticCurveAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = getEllipticCurveType() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Special cased to address the fact that arg index 3 (zero offset based) is the curve name.
|
||||
* ASSUMPTION: if the arg ind 3 is a char* assume it is an elliptic curve
|
||||
*/
|
||||
class EllipticCurveAlgorithmSink_EVP_PKEY_Q_keygen extends AlgorithmSinkArgument {
|
||||
EllipticCurveAlgorithmSink_EVP_PKEY_Q_keygen() {
|
||||
exists(Call c, string funcName |
|
||||
funcName = c.getTarget().getName() and
|
||||
this = c.getArgument(3)
|
||||
|
|
||||
funcName = "EVP_PKEY_Q_keygen" and
|
||||
c.getArgument(3).getType().getUnderlyingType() instanceof PointerType and
|
||||
c.getArgument(3).getType().getUnderlyingType().stripType() instanceof CharType
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = getEllipticCurveType() }
|
||||
}
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_new_id.html
|
||||
// https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_new_raw_private_key.html
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_new.html
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_ctrl.html
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_Q_keygen.html
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_ctrl.html
|
||||
predicate asymmetricAlgorithmSink(string funcName, int argInd) {
|
||||
funcName = "EVP_PKEY_CTX_new_id" and argInd = 0
|
||||
or
|
||||
funcName = "EVP_PKEY_CTX_new_from_name" and argInd = 1
|
||||
or
|
||||
funcName in [
|
||||
"EVP_PKEY_new_raw_private_key", "EVP_PKEY_new_raw_public_key", "EVP_PKEY_new_mac_key"
|
||||
] and
|
||||
argInd = 0
|
||||
or
|
||||
funcName in ["EVP_PKEY_new_raw_private_key_ex", "EVP_PKEY_new_raw_public_key_ex"] and argInd = 1
|
||||
or
|
||||
// special casing this as arg index 3 must be specified depending on if RSA or ECC, and otherwise not specified for other algs
|
||||
// funcName = "EVP_PKEY_Q_keygen" and argInd = 2
|
||||
funcName in ["EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_set_group_name"] and argInd = 1
|
||||
// TODO consider void cases EVP_PKEY_new
|
||||
}
|
||||
|
||||
class AsymmetricAlgorithmSink extends AlgorithmSinkArgument {
|
||||
AsymmetricAlgorithmSink() {
|
||||
exists(Call c, string funcName, int argInd |
|
||||
funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
|
|
||||
asymmetricAlgorithmSink(funcName, argInd)
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = getAsymmetricType() }
|
||||
}
|
||||
|
||||
class AsymmetricAlgorithmSink_EVP_PKEY_Q_keygen extends AlgorithmSinkArgument {
|
||||
AsymmetricAlgorithmSink_EVP_PKEY_Q_keygen() {
|
||||
exists(Call c, string funcName |
|
||||
funcName = c.getTarget().getName() and
|
||||
this = c.getArgument(2)
|
||||
|
|
||||
funcName = "EVP_PKEY_Q_keygen" and
|
||||
not exists(c.getArgument(3))
|
||||
)
|
||||
}
|
||||
|
||||
override string algType() { result = getAsymmetricType() }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,121 @@
|
||||
import cpp
|
||||
import experimental.cryptography.utils.OpenSSL.LibraryFunction
|
||||
import experimental.cryptography.CryptoAlgorithmNames
|
||||
|
||||
predicate inferredOpenSSLCryptoFunctionCall(Call c, string normalized, string algType) {
|
||||
inferredOpenSSLCryptoFunction(c.getTarget(), normalized, algType)
|
||||
}
|
||||
|
||||
predicate inferredOpenSSLCryptoFunction(Function f, string normalized, string algType) {
|
||||
isPossibleOpenSSLFunction(f) and
|
||||
normalizeFunctionName(f, algType) = normalized
|
||||
}
|
||||
|
||||
predicate isOpenSSLCryptoFunction(Function f, string normalized, string algType) {
|
||||
// NOTE: relying on inference as there are thousands of functions for crypto
|
||||
// enumerating them all and maintaining the list seems problematic.
|
||||
// For now, we will rely on dynamically inferring algorithms for function names.
|
||||
// This has been seen to be reasonably efficient and accurate.
|
||||
inferredOpenSSLCryptoFunction(f, normalized, algType)
|
||||
}
|
||||
|
||||
predicate isOpenSSLCryptoFunctionCall(Call c, string normalized, string algType) {
|
||||
isOpenSSLCryptoFunction(c.getTarget(), normalized, algType)
|
||||
}
|
||||
|
||||
private string basicNormalizeFunctionName(Function f, string algType) {
|
||||
isPossibleOpenSSLFunction(f) and
|
||||
isKnownAlgorithm(result, algType) and
|
||||
exists(string normStr | normStr = f.getName().toUpperCase().regexpReplaceAll("[-_ ]|/", "") |
|
||||
normStr.matches("%" + result + "%")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a raw OpenSSL algorithm to a normalized algorithm name.
|
||||
*
|
||||
* If more than one match occurs for a given algorithm type, normalize attempts to find the "max"
|
||||
* string (max in terms of string length) e.g., matching AES128 to AES128 and not simply AES.
|
||||
*
|
||||
* An unknown algorithm is only identified if there exists no known algorithm found for any algorithm type.
|
||||
*
|
||||
* `f` is the function name to normalize.
|
||||
* `algType` is a string representing the classification of the algorithm (see `CryptoAlgorithmNames`)
|
||||
*/
|
||||
private string privateNormalizeFunctionName(Function f, string algType) {
|
||||
isPossibleOpenSSLFunction(f) and
|
||||
result = basicNormalizeFunctionName(f, algType) and
|
||||
not exists(string res2 |
|
||||
result != res2 and
|
||||
res2 = basicNormalizeFunctionName(f, algType) and
|
||||
res2.length() > result.length()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a function name to a known algorithm name, similar to `normalizeName`.
|
||||
* A function is not, however, allowed to be UNKNOWN. The function either
|
||||
* normalizes to a known algorithm name, or the predicate does not hold (no result).
|
||||
*
|
||||
* The predicate attempts to restrict normalization to what looks like an openssl
|
||||
* library by looking for functions only in an openssl path (see `isPossibleOpenSSLFunction`).
|
||||
* This may give false postive functions if a directory erronously appears to be openssl;
|
||||
* however, we take the stance that if a function
|
||||
* exists strongly mapping to a known function name in a directory such as these,
|
||||
* regardless of whether its actually a part of openSSL or not, we will analyze it as though it were.
|
||||
*/
|
||||
private string normalizeFunctionName(Function f, string algType) {
|
||||
algType != "UNKNOWN" and
|
||||
isPossibleOpenSSLFunction(f) and
|
||||
result = privateNormalizeFunctionName(f, algType) and
|
||||
// Addressing false positives
|
||||
// For algorithm names less than or equal to 4, we must see the algorithm name
|
||||
// in the original function as upper case (it can't be split between tokens)
|
||||
// One exception found is DES_xcbc_encrypt, this is DESX
|
||||
(
|
||||
(result.length() <= 4 and result != "DESX")
|
||||
implies
|
||||
f.getName().toUpperCase().matches("%" + result + "%")
|
||||
) and
|
||||
(
|
||||
(result.length() <= 4 and result = "DESX")
|
||||
implies
|
||||
(f.getName().toUpperCase().matches("%DESX%") or f.getName().toUpperCase().matches("%DES_X%"))
|
||||
) and
|
||||
// (result.length() <= 3 implies (not f.getName().toUpperCase().regexpMatch(".*" + result + "[a-zA-Z0-9].*|.*[a-zA-Z0-9]" + result + ".*")))
|
||||
// and
|
||||
// DES specific false positives
|
||||
(
|
||||
result.matches("DES")
|
||||
implies
|
||||
not f.getName().toUpperCase().regexpMatch(".*DES[a-zA-Z0-9].*|.*[a-zA-Z0-9]DES.*")
|
||||
) and
|
||||
// ((result.matches("%DES%")) implies not exists(string s | s in ["DESCRIBE", "DESTROY", "DESCRIPTION", "DESCRIPTOR", "NODES"] |
|
||||
// f.getName().toUpperCase().matches("%" + s + "%"))) and
|
||||
// SEED specific false positives
|
||||
(
|
||||
result.matches("SEED")
|
||||
implies
|
||||
not exists(string s |
|
||||
s in [
|
||||
"SEED_SRC_GENERATE", "RAND", "NEW_SEED", "GEN_SEED", "SEED_GEN", "SET_SEED", "GET_SEED",
|
||||
"GET0_SEED", "RESEED", "SEEDING"
|
||||
]
|
||||
|
|
||||
f.getName().toUpperCase().matches("%" + s + "%")
|
||||
)
|
||||
) and
|
||||
// ARIA specific false positives
|
||||
(result.matches("ARIA") implies not f.getName().toUpperCase().matches("%VARIANT%")) and
|
||||
// CTR false positives
|
||||
(result.matches("CTR") implies not f.getName().toUpperCase().matches("%CTRL%")) and
|
||||
// ES false positives (e.g., ES256 from AES256)
|
||||
(result.matches("ES%") implies not f.getName().toUpperCase().matches("%AES%")) and
|
||||
// RSA false positives
|
||||
(result.matches("RSA") implies not f.getName().toUpperCase().matches("%UNIVERSAL%")) and
|
||||
//rsaz functions deemed to be too low level, and can be ignored
|
||||
not f.getLocation().getFile().getBaseName().matches("rsaz_exp.c") and
|
||||
// General False positives
|
||||
// Functions that 'get' do not set an algorithm, and therefore are considered ignorable
|
||||
not f.getName().toLowerCase().matches("%get%")
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* This file contains predicates create to build up initial data sets for OpenSSL
|
||||
* predicates. E.g., These predicates were used to assist in associating all
|
||||
* openSSL functions with their known crypto algorithms.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.CryptoAlgorithmNames
|
||||
import experimental.cryptography.utils.OpenSSL.CryptoFunction
|
||||
|
||||
private string basicNormalizeFunctionName(Function f, string algType) {
|
||||
isKnownAlgorithm(result, algType) and
|
||||
exists(string normStr | normStr = f.getName().toUpperCase().regexpReplaceAll("[-_ ]|/", "") |
|
||||
normStr.matches("%" + result + "%")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a raw OpenSSL algorithm to a normalized algorithm name.
|
||||
*
|
||||
* If more than one match occurs for a given algorithm type, normalize attempts to find the "max"
|
||||
* string (max in terms of string length) e.g., matching AES128 to AES128 and not simply AES.
|
||||
*
|
||||
* An unknown algorithm is only identified if there exists no known algorithm found for any algorithm type.
|
||||
*
|
||||
* `f` is the function name to normalize.
|
||||
* `algType` is a string representing the classification of the algorithm (see `CryptoAlgorithmNames`)
|
||||
*/
|
||||
private string privateNormalizeFunctionName(Function f, string algType) {
|
||||
result = basicNormalizeFunctionName(f, algType) and
|
||||
not exists(string res2 |
|
||||
result != res2 and
|
||||
res2 = basicNormalizeFunctionName(f, algType) and
|
||||
res2.length() > result.length()
|
||||
) and
|
||||
// Addressing bad normalization case-by-case
|
||||
// CASE: ES256 being identified when the algorithm is AES256
|
||||
(
|
||||
result.matches("ES256")
|
||||
implies
|
||||
not exists(string res2 | res2 = basicNormalizeFunctionName(f, _) and res2.matches("AES%"))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a function name to a known algorithm name, similar to `normalizeName`.
|
||||
* A function is not, however, allowed to be UNKNOWN. The function either
|
||||
* normalizes to a known algorithm name, or the predicate does not hold (no result).
|
||||
*
|
||||
* The predicate attempts to restrict normalization to what looks like an openssl
|
||||
* library by looking for functions only in an openssl path (see `isPossibleOpenSSLFunction`).
|
||||
* This may give false postive functions if a directory erronously appears to be openssl;
|
||||
* however, we take the stance that if a function
|
||||
* exists strongly mapping to a known function name in a directory such as these,
|
||||
* regardless of whether its actually a part of openSSL or not, we will analyze it as though it were.
|
||||
*/
|
||||
string normalizeFunctionName(Function f, string algType) {
|
||||
algType != "UNKNOWN" and
|
||||
result = privateNormalizeFunctionName(f, algType) and
|
||||
openSSLLibraryFunc(f) and
|
||||
// Addressing false positives
|
||||
// For algorithm names less than or equal to 4, we must see the algorithm name
|
||||
// in the original function as upper case (it can't be split between tokens)
|
||||
// One exception found is DES_xcbc_encrypt, this is DESX
|
||||
(
|
||||
(result.length() <= 4 and result != "DESX")
|
||||
implies
|
||||
f.getName().toUpperCase().matches("%" + result + "%")
|
||||
) and
|
||||
(
|
||||
(result.length() <= 4 and result = "DESX")
|
||||
implies
|
||||
(f.getName().toUpperCase().matches("%DESX%") or f.getName().toUpperCase().matches("%DES_X%"))
|
||||
) and
|
||||
// (result.length() <= 3 implies (not f.getName().toUpperCase().regexpMatch(".*" + result + "[a-zA-Z0-9].*|.*[a-zA-Z0-9]" + result + ".*")))
|
||||
// and
|
||||
// DES specific false positives
|
||||
(
|
||||
result.matches("DES")
|
||||
implies
|
||||
not f.getName().toUpperCase().regexpMatch(".*DES[a-zA-Z0-9].*|.*[a-zA-Z0-9]DES.*")
|
||||
) and
|
||||
// ((result.matches("%DES%")) implies not exists(string s | s in ["DESCRIBE", "DESTROY", "DESCRIPTION", "DESCRIPTOR", "NODES"] |
|
||||
// f.getName().toUpperCase().matches("%" + s + "%"))) and
|
||||
// SEED specific false positives
|
||||
(
|
||||
result.matches("%SEED%")
|
||||
implies
|
||||
not not exists(string s |
|
||||
s in ["NEW_SEED", "GEN_SEED", "SET_SEED", "GET_SEED", "GET0_SEED", "RESEED", "SEEDING"]
|
||||
|
|
||||
f.getName().toUpperCase().matches("%" + s + "%")
|
||||
)
|
||||
) and
|
||||
// ARIA specific false positives
|
||||
(result.matches("%ARIA%") implies not f.getName().toUpperCase().matches("%VARIANT%"))
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to support name normalization.
|
||||
* Converts the raw name upper-case with no hyphen, slash, underscore, hash, or space.
|
||||
* Looks for substrings that are known algorithms, and normalizes the name.
|
||||
* If the algorithm cannot be determined or is in the ignorable list (`isIgnorableOpenSSLAlgorithm`)
|
||||
* this predicate will not resolve a name.
|
||||
*
|
||||
* Rationale for private: For normalization, we want to get the longest string for a normalized name match
|
||||
* for a given algorithm type. I found this easier to express if the public normalizeName
|
||||
* checks that the name is the longest, and that UNKNOWN is reserved if there exists no
|
||||
* result from this predicate that is known.
|
||||
*/
|
||||
bindingset[name]
|
||||
string privateNormalizeName(string name, string algType) {
|
||||
//not isIgnorableOpenSSLAlgorithm(name, _, _) and
|
||||
// targetOpenSSLAlgorithm(name, _) and
|
||||
isKnownAlgorithm(result, algType) and
|
||||
exists(string normStr | normStr = name.toUpperCase().regexpReplaceAll("[-_ ]|/", "") |
|
||||
normStr.matches("%" + result + "%")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a raw OpenSSL algorithm to a normalized algorithm name.
|
||||
*
|
||||
* If more than one match occurs for a given algorithm type, normalize attempts to find the "max"
|
||||
* string (max in terms of string length) e.g., matching AES128 to AES128 and not simply AES.
|
||||
*
|
||||
* An unknown algorithm is only identified if there exists no known algorithm found for any algorithm type.
|
||||
*
|
||||
* `name` is the name to normalize.
|
||||
* `algType` is a string representing the classification of the algorithm (see `CryptoAlgorithmNames`)
|
||||
*/
|
||||
bindingset[name]
|
||||
string normalizeName(string name, string algType) {
|
||||
(
|
||||
if exists(privateNormalizeName(name, _))
|
||||
then result = privateNormalizeName(name, algType)
|
||||
else (
|
||||
result = unknownAlgorithm() and algType = "UNKNOWN"
|
||||
)
|
||||
) and
|
||||
not exists(string res2 |
|
||||
result != res2 and
|
||||
res2 = privateNormalizeName(name, algType) and
|
||||
res2.length() > result.length()
|
||||
) and
|
||||
// Addressing bad normalization case-by-case
|
||||
// CASE: ES256 being identified when the algorithm is AES256
|
||||
(
|
||||
result.matches("ES256")
|
||||
implies
|
||||
not exists(string res2 | res2 = privateNormalizeName(name, _) and res2.matches("AES%"))
|
||||
)
|
||||
}
|
||||
11292
cpp/ql/lib/experimental/cryptography/utils/OpenSSL/LibraryFunction.qll
Normal file
11292
cpp/ql/lib/experimental/cryptography/utils/OpenSSL/LibraryFunction.qll
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
import cpp
|
||||
import experimental.cryptography.utils.OpenSSL.LibraryFunction
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
|
||||
// TODO: possible use of extensible predicates here
|
||||
// NOTE: -1 for outInd represents the return value
|
||||
predicate knownPassthroughFunction(Function f, int inInd, int outInd) {
|
||||
// Trace through functions
|
||||
// See https://www.openssl.org/docs/man1.1.1/man3/OBJ_obj2txt
|
||||
// https://www.openssl.org/docs/man3.0/man3/EVP_CIPHER_get0_name
|
||||
openSSLLibraryFunc(f) and
|
||||
(
|
||||
f.getName() in [
|
||||
"OBJ_nid2obj", "OBJ_nid2ln", "OBJ_nid2sn", "OBJ_obj2nid", "OBJ_ln2nid", "OBJ_sn2nid",
|
||||
"OBJ_txt2nid", "OBJ_txt2obj", "OBJ_dup", "EVP_CIPHER_get0_name"
|
||||
] and
|
||||
inInd = 0 and
|
||||
outInd = -1
|
||||
or
|
||||
f.getName() in ["OBJ_obj2txt", "i2t_ASN1_OBJECT"] and
|
||||
inInd = 2 and
|
||||
outInd = 0
|
||||
or
|
||||
// Dup/copy pattern occurs in more places,
|
||||
//see: https://www.openssl.org/docs/manmaster/man3/EC_KEY_copy.html and https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_dup.html
|
||||
f.getName().matches("%_dup") and inInd = 0 and outInd = -1
|
||||
or
|
||||
f.getName().matches("%_copy") and inInd = 0 and outInd = -1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* `c` is a call to a function that preserves the algorithm but changes its form.
|
||||
* `onExpr` is the input argument passing through to, `outExpr` is the next expression in a dataflow step associated with `c`
|
||||
*/
|
||||
predicate knownPassthoughCall(Call c, Expr inExpr, Expr outExpr) {
|
||||
exists(int inInd, int outInd |
|
||||
knownPassthroughFunction(c.getTarget(), inInd, outInd) and
|
||||
inExpr = c.getArgument(inInd) and
|
||||
if outInd = -1 then outExpr = c else outExpr = c.getArgument(outInd)
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* Explicitly add flow through openssl functions that preserve the algorithm but alter the form (e.g., from NID to string)
|
||||
*/
|
||||
|
||||
predicate knownPassThroughStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(Expr cur, Expr next |
|
||||
(cur = node1.asExpr() or cur = node1.asIndirectArgument()) and
|
||||
(
|
||||
next = node2.asExpr() or
|
||||
next = node2.asIndirectArgument() or
|
||||
next = node2.asDefiningArgument()
|
||||
)
|
||||
|
|
||||
exists(Call c | knownPassthoughCall(c, cur, next))
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.10.0-dev
|
||||
version: 0.10.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -158,9 +158,7 @@ class NameQualifyingElement extends Element, @namequalifyingelement {
|
||||
/**
|
||||
* A special name-qualifying element. For example: `__super`.
|
||||
*/
|
||||
library class SpecialNameQualifyingElement extends NameQualifyingElement,
|
||||
@specialnamequalifyingelement
|
||||
{
|
||||
class SpecialNameQualifyingElement extends NameQualifyingElement, @specialnamequalifyingelement {
|
||||
/** Gets the name of this special qualifying element. */
|
||||
override string getName() { specialnamequalifyingelements(underlyingElement(this), result) }
|
||||
|
||||
|
||||
@@ -73,6 +73,10 @@ private int isSource(Expr bufferExpr, Element why) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Same as `getBufferSize`, but with the `why` column projected away to prevent large duplications. */
|
||||
pragma[nomagic]
|
||||
int getBufferSizeProj(Expr bufferExpr) { result = getBufferSize(bufferExpr, _) }
|
||||
|
||||
/**
|
||||
* Get the size in bytes of the buffer pointed to by an expression (if this can be determined).
|
||||
*/
|
||||
@@ -87,7 +91,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
why = bufferVar and
|
||||
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
|
||||
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
||||
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
|
||||
result = getBufferSizeProj(parentPtr) + bufferSize - parentClass.getSize()
|
||||
|
|
||||
if exists(bufferVar.getType().getSize())
|
||||
then bufferSize = bufferVar.getType().getSize()
|
||||
@@ -95,7 +99,6 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
)
|
||||
or
|
||||
// dataflow (all sources must be the same size)
|
||||
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSize(def, _)) and
|
||||
// find reason
|
||||
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSizeProj(def)) and
|
||||
exists(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | exists(getBufferSize(def, why)))
|
||||
}
|
||||
|
||||
@@ -27,9 +27,6 @@ predicate canValueFlow(Expr fromExpr, Expr toExpr) {
|
||||
fromExpr = toExpr.(ConditionalExpr).getElse()
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AnalyzedString */
|
||||
deprecated class AnalysedString = AnalyzedString;
|
||||
|
||||
/**
|
||||
* An analyzed null terminated string.
|
||||
*/
|
||||
|
||||
@@ -78,7 +78,7 @@ predicate parameterUsePair(Parameter p, VariableAccess va) {
|
||||
/**
|
||||
* Utility class: A definition or use of a stack variable.
|
||||
*/
|
||||
library class DefOrUse extends ControlFlowNodeBase {
|
||||
class DefOrUse extends ControlFlowNodeBase {
|
||||
DefOrUse() {
|
||||
// Uninstantiated templates are purely syntax, and only on instantiation
|
||||
// will they be complete with information about types, conversions, call
|
||||
@@ -140,7 +140,7 @@ library class DefOrUse extends ControlFlowNodeBase {
|
||||
}
|
||||
|
||||
/** A definition of a stack variable. */
|
||||
library class Def extends DefOrUse {
|
||||
class Def extends DefOrUse {
|
||||
Def() { definition(_, this) }
|
||||
|
||||
override SemanticStackVariable getVariable(boolean isDef) {
|
||||
@@ -155,7 +155,7 @@ private predicate parameterIsOverwritten(Function f, Parameter p) {
|
||||
}
|
||||
|
||||
/** A definition of a parameter. */
|
||||
library class ParameterDef extends DefOrUse {
|
||||
class ParameterDef extends DefOrUse {
|
||||
ParameterDef() {
|
||||
// Optimization: parameters that are not overwritten do not require
|
||||
// reachability analysis
|
||||
@@ -169,7 +169,7 @@ library class ParameterDef extends DefOrUse {
|
||||
}
|
||||
|
||||
/** A use of a stack variable. */
|
||||
library class Use extends DefOrUse {
|
||||
class Use extends DefOrUse {
|
||||
Use() { useOfVar(_, this) }
|
||||
|
||||
override SemanticStackVariable getVariable(boolean isDef) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import SSAUtils
|
||||
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
|
||||
* This class provides the standard SSA logic.
|
||||
*/
|
||||
library class StandardSsa extends SsaHelper {
|
||||
class StandardSsa extends SsaHelper {
|
||||
StandardSsa() { this = 0 }
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ private predicate live_at_exit_of_bb(StackVariable v, BasicBlock b) {
|
||||
|
||||
/** Common SSA logic for standard SSA and range-analysis SSA. */
|
||||
cached
|
||||
library class SsaHelper extends int {
|
||||
class SsaHelper extends int {
|
||||
/* 0 = StandardSSA, 1 = RangeSSA */
|
||||
cached
|
||||
SsaHelper() { this in [0 .. 1] }
|
||||
|
||||
@@ -366,12 +366,12 @@ class CompileTimeConstantInt extends Expr {
|
||||
int getIntValue() { result = val }
|
||||
}
|
||||
|
||||
library class CompileTimeVariableExpr extends Expr {
|
||||
class CompileTimeVariableExpr extends Expr {
|
||||
CompileTimeVariableExpr() { not this instanceof CompileTimeConstantInt }
|
||||
}
|
||||
|
||||
/** A helper class for evaluation of expressions. */
|
||||
library class ExprEvaluator extends int {
|
||||
class ExprEvaluator extends int {
|
||||
/*
|
||||
* 0 = ConditionEvaluator,
|
||||
* 1 = SwitchEvaluator,
|
||||
@@ -956,7 +956,7 @@ private predicate returnStmt(Function f, Expr value) {
|
||||
}
|
||||
|
||||
/** A helper class for evaluation of conditions. */
|
||||
library class ConditionEvaluator extends ExprEvaluator {
|
||||
class ConditionEvaluator extends ExprEvaluator {
|
||||
ConditionEvaluator() { this = 0 }
|
||||
|
||||
override predicate interesting(Expr e) {
|
||||
@@ -967,7 +967,7 @@ library class ConditionEvaluator extends ExprEvaluator {
|
||||
}
|
||||
|
||||
/** A helper class for evaluation of switch expressions. */
|
||||
library class SwitchEvaluator extends ExprEvaluator {
|
||||
class SwitchEvaluator extends ExprEvaluator {
|
||||
SwitchEvaluator() { this = 1 }
|
||||
|
||||
override predicate interesting(Expr e) { e = getASwitchExpr(_, _) }
|
||||
@@ -976,7 +976,7 @@ library class SwitchEvaluator extends ExprEvaluator {
|
||||
private int getSwitchValue(Expr e) { exists(SwitchEvaluator x | result = x.getValue(e)) }
|
||||
|
||||
/** A helper class for evaluation of loop entry conditions. */
|
||||
library class LoopEntryConditionEvaluator extends ExprEvaluator {
|
||||
class LoopEntryConditionEvaluator extends ExprEvaluator {
|
||||
LoopEntryConditionEvaluator() { this in [2 .. 3] }
|
||||
|
||||
abstract override predicate interesting(Expr e);
|
||||
@@ -1149,7 +1149,7 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
|
||||
}
|
||||
|
||||
/** A helper class for evaluation of while-loop entry conditions. */
|
||||
library class WhileLoopEntryConditionEvaluator extends LoopEntryConditionEvaluator {
|
||||
class WhileLoopEntryConditionEvaluator extends LoopEntryConditionEvaluator {
|
||||
WhileLoopEntryConditionEvaluator() { this = 2 }
|
||||
|
||||
override predicate interesting(Expr e) { exists(WhileStmt while | e = while.getCondition()) }
|
||||
@@ -1162,7 +1162,7 @@ library class WhileLoopEntryConditionEvaluator extends LoopEntryConditionEvaluat
|
||||
}
|
||||
|
||||
/** A helper class for evaluation of for-loop entry conditions. */
|
||||
library class ForLoopEntryConditionEvaluator extends LoopEntryConditionEvaluator {
|
||||
class ForLoopEntryConditionEvaluator extends LoopEntryConditionEvaluator {
|
||||
ForLoopEntryConditionEvaluator() { this = 3 }
|
||||
|
||||
override predicate interesting(Expr e) { exists(ForStmt for | e = for.getCondition()) }
|
||||
|
||||
@@ -91,21 +91,6 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
@@ -225,29 +210,6 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
@@ -288,9 +250,7 @@ private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
@@ -91,21 +91,6 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
@@ -225,29 +210,6 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
@@ -288,9 +250,7 @@ private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
@@ -91,21 +91,6 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
@@ -225,29 +210,6 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
@@ -288,9 +250,7 @@ private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
@@ -91,21 +91,6 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
@@ -225,29 +210,6 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
@@ -288,9 +250,7 @@ private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
@@ -91,21 +91,6 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
@@ -225,29 +210,6 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
@@ -288,9 +250,7 @@ private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
@@ -874,28 +874,3 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BarrierGuard` module instead.
|
||||
*
|
||||
* A guard that validates some expression.
|
||||
*
|
||||
* To use this in a configuration, extend the class and provide a
|
||||
* characteristic predicate precisely specifying the guard, and override
|
||||
* `checks` to specify what is being validated and in which branch.
|
||||
*
|
||||
* It is important that all extending classes in scope are disjoint.
|
||||
*/
|
||||
deprecated class BarrierGuard extends GuardCondition {
|
||||
/** Override this predicate to hold if this guard validates `e` upon evaluating to `b`. */
|
||||
abstract predicate checks(Expr e, boolean b);
|
||||
|
||||
/** Gets a node guarded by this guard. */
|
||||
final ExprNode getAGuardedNode() {
|
||||
exists(SsaDefinition def, Variable v, boolean branch |
|
||||
result.getExpr() = def.getAUse(v) and
|
||||
this.checks(def.getAUse(v), branch) and
|
||||
this.controls(result.getExpr().getBasicBlock(), branch)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,33 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||
* when the flow state is `state`.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
none()
|
||||
}
|
||||
|
||||
deprecated final override predicate isBarrierGuard(
|
||||
DataFlow::BarrierGuard guard, DataFlow::FlowState state
|
||||
) {
|
||||
this.isSanitizerGuard(guard, state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
|
||||
@@ -116,33 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||
* when the flow state is `state`.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
none()
|
||||
}
|
||||
|
||||
deprecated final override predicate isBarrierGuard(
|
||||
DataFlow::BarrierGuard guard, DataFlow::FlowState state
|
||||
) {
|
||||
this.isSanitizerGuard(guard, state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
|
||||
@@ -91,21 +91,6 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
@@ -225,29 +210,6 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
@@ -288,9 +250,7 @@ private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
@@ -91,21 +91,6 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
@@ -225,29 +210,6 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
@@ -288,9 +250,7 @@ private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
@@ -91,21 +91,6 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
@@ -225,29 +210,6 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
@@ -288,9 +250,7 @@ private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
@@ -91,21 +91,6 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
@@ -225,29 +210,6 @@ abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
@@ -288,9 +250,7 @@ private module Config implements FullStateConfigSig {
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
@@ -555,7 +555,7 @@ predicate instructionForFullyConvertedCall(Instruction instr, CallInstruction ca
|
||||
}
|
||||
|
||||
/** Holds if `node` represents the output node for `call`. */
|
||||
private predicate simpleOutNode(Node node, CallInstruction call) {
|
||||
predicate simpleOutNode(Node node, CallInstruction call) {
|
||||
operandForFullyConvertedCall(node.asOperand(), call)
|
||||
or
|
||||
instructionForFullyConvertedCall(node.asInstruction(), call)
|
||||
|
||||
@@ -1696,16 +1696,7 @@ private module Cached {
|
||||
// Reverse flow: data that flows from the definition node back into the indirection returned
|
||||
// by a function. This allows data to flow 'in' through references returned by a modeled
|
||||
// function such as `operator[]`.
|
||||
exists(Operand address, int indirectionIndex |
|
||||
nodeHasOperand(nodeTo.(IndirectReturnOutNode), address, indirectionIndex)
|
||||
|
|
||||
exists(StoreInstruction store |
|
||||
nodeHasInstruction(nodeFrom, store, indirectionIndex - 1) and
|
||||
store.getDestinationAddressOperand() = address
|
||||
)
|
||||
or
|
||||
Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
|
||||
)
|
||||
reverseFlow(nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) {
|
||||
@@ -1736,6 +1727,39 @@ private module Cached {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate reverseFlow(Node nodeFrom, Node nodeTo) {
|
||||
reverseFlowOperand(nodeFrom, nodeTo)
|
||||
or
|
||||
reverseFlowInstruction(nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
private predicate reverseFlowOperand(Node nodeFrom, IndirectReturnOutNode nodeTo) {
|
||||
exists(Operand address, int indirectionIndex |
|
||||
nodeHasOperand(nodeTo, address, indirectionIndex)
|
||||
|
|
||||
exists(StoreInstruction store |
|
||||
nodeHasInstruction(nodeFrom, store, indirectionIndex - 1) and
|
||||
store.getDestinationAddressOperand() = address
|
||||
)
|
||||
or
|
||||
// We also want a write coming out of an `OutNode` to flow `nodeTo`.
|
||||
// This is different from `reverseFlowInstruction` since `nodeFrom` can never
|
||||
// be an `OutNode` when it's defined by an instruction.
|
||||
Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate reverseFlowInstruction(Node nodeFrom, IndirectReturnOutNode nodeTo) {
|
||||
exists(Instruction address, int indirectionIndex |
|
||||
nodeHasInstruction(nodeTo, address, indirectionIndex)
|
||||
|
|
||||
exists(StoreInstruction store |
|
||||
nodeHasInstruction(nodeFrom, store, indirectionIndex - 1) and
|
||||
store.getDestinationAddress() = address
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -2213,35 +2237,3 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BarrierGuard` module instead.
|
||||
*
|
||||
* A guard that validates some instruction.
|
||||
*
|
||||
* To use this in a configuration, extend the class and provide a
|
||||
* characteristic predicate precisely specifying the guard, and override
|
||||
* `checks` to specify what is being validated and in which branch.
|
||||
*
|
||||
* It is important that all extending classes in scope are disjoint.
|
||||
*/
|
||||
deprecated class BarrierGuard extends IRGuardCondition {
|
||||
/** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */
|
||||
predicate checksInstr(Instruction instr, boolean b) { none() }
|
||||
|
||||
/** Override this predicate to hold if this guard validates `expr` upon evaluating to `b`. */
|
||||
predicate checks(Expr e, boolean b) { none() }
|
||||
|
||||
/** Gets a node guarded by this guard. */
|
||||
final Node getAGuardedNode() {
|
||||
exists(ValueNumber value, boolean edge |
|
||||
(
|
||||
this.checksInstr(value.getAnInstruction(), edge)
|
||||
or
|
||||
this.checks(value.getAnInstruction().getConvertedResultExpression(), edge)
|
||||
) and
|
||||
result.asInstruction() = value.getAnInstruction() and
|
||||
this.controls(result.asInstruction().getBlock(), edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import SsaInternals as Ssa
|
||||
|
||||
/**
|
||||
@@ -35,7 +36,7 @@ DataFlow::Node callInput(CallInstruction call, FunctionInput input) {
|
||||
*/
|
||||
Node callOutput(CallInstruction call, FunctionOutput output) {
|
||||
// The return value
|
||||
result.asInstruction() = call and
|
||||
simpleOutNode(result, call) and
|
||||
output.isReturnValue()
|
||||
or
|
||||
// The side effect of a call on the value pointed to by an argument or qualifier
|
||||
@@ -82,7 +83,7 @@ Node callOutput(CallInstruction call, FunctionOutput output, int d) {
|
||||
// If there isn't an indirect out node for the call with indirection `d` then
|
||||
// we conflate this with the underlying `CallInstruction`.
|
||||
not exists(getIndirectReturnOutNode(call, d)) and
|
||||
n.asInstruction() = result.asInstruction()
|
||||
n = result
|
||||
or
|
||||
// The side effect of a call on the value pointed to by an argument or qualifier
|
||||
exists(Operand operand, int indirectionIndex |
|
||||
|
||||
@@ -374,6 +374,8 @@ module ProductFlow {
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { Config::isBarrier1(node, state) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { Config::isBarrier1(node) }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { Config::isBarrierOut1(node) }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
@@ -408,6 +410,8 @@ module ProductFlow {
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { Config::isBarrier2(node, state) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { Config::isBarrier2(node) }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { Config::isBarrierOut2(node) }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
|
||||
@@ -815,7 +815,7 @@ private module Cached {
|
||||
) {
|
||||
indirectionIndex = [1 .. countIndirectionsForCppType(getResultLanguageType(instr))] and
|
||||
exists(Instruction load, Operand address |
|
||||
address.getDef() = instr and
|
||||
address = unique( | | getAUse(instr)) and
|
||||
isDereference(load, address, false) and
|
||||
instrRepr = load and
|
||||
indirectionIndexRepr = indirectionIndex - 1
|
||||
|
||||
@@ -116,33 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||
* when the flow state is `state`.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
none()
|
||||
}
|
||||
|
||||
deprecated final override predicate isBarrierGuard(
|
||||
DataFlow::BarrierGuard guard, DataFlow::FlowState state
|
||||
) {
|
||||
this.isSanitizerGuard(guard, state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
|
||||
@@ -116,33 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||
* when the flow state is `state`.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
none()
|
||||
}
|
||||
|
||||
deprecated final override predicate isBarrierGuard(
|
||||
DataFlow::BarrierGuard guard, DataFlow::FlowState state
|
||||
) {
|
||||
this.isSanitizerGuard(guard, state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
|
||||
@@ -116,33 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||
* when the flow state is `state`.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
none()
|
||||
}
|
||||
|
||||
deprecated final override predicate isBarrierGuard(
|
||||
DataFlow::BarrierGuard guard, DataFlow::FlowState state
|
||||
) {
|
||||
this.isSanitizerGuard(guard, state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,22 @@ private import internal.IRBlockImports as Imports
|
||||
import Imports::EdgeKind
|
||||
private import Cached
|
||||
|
||||
/**
|
||||
* Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the
|
||||
* sort keys of the block (derived from its first instruction)
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate blockSortKeys(
|
||||
IRFunction func, IRBlockBase block, int sortOverride, int sortKey1, int sortKey2
|
||||
) {
|
||||
block.getEnclosingIRFunction() = func and
|
||||
block.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
||||
// Ensure that the block containing `EnterFunction` always comes first.
|
||||
if block.getFirstInstruction() instanceof EnterFunctionInstruction
|
||||
then sortOverride = 0
|
||||
else sortOverride = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
|
||||
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
|
||||
@@ -37,17 +53,14 @@ class IRBlockBase extends TIRBlock {
|
||||
exists(IRConfiguration::IRConfiguration config |
|
||||
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
|
||||
) and
|
||||
this =
|
||||
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
||||
funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and
|
||||
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
||||
// Ensure that the block containing `EnterFunction` always comes first.
|
||||
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
|
||||
then sortOverride = 0
|
||||
else sortOverride = 1
|
||||
|
|
||||
funcBlock order by sortOverride, sortKey1, sortKey2
|
||||
)
|
||||
exists(IRFunction func |
|
||||
this =
|
||||
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
||||
blockSortKeys(func, funcBlock, sortOverride, sortKey1, sortKey2)
|
||||
|
|
||||
funcBlock order by sortOverride, sortKey1, sortKey2
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,14 +116,14 @@ class Instruction extends Construction::TStageInstruction {
|
||||
|
||||
private int getLineRank() {
|
||||
this.shouldGenerateDumpStrings() and
|
||||
this =
|
||||
rank[result](Instruction instr |
|
||||
instr =
|
||||
getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(),
|
||||
this.getLocation().getStartLine())
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
exists(IRFunction enclosing, Language::File file, int line |
|
||||
this =
|
||||
rank[result](Instruction instr |
|
||||
instr = getAnInstructionAtLine(enclosing, file, line)
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,22 @@ private import internal.IRBlockImports as Imports
|
||||
import Imports::EdgeKind
|
||||
private import Cached
|
||||
|
||||
/**
|
||||
* Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the
|
||||
* sort keys of the block (derived from its first instruction)
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate blockSortKeys(
|
||||
IRFunction func, IRBlockBase block, int sortOverride, int sortKey1, int sortKey2
|
||||
) {
|
||||
block.getEnclosingIRFunction() = func and
|
||||
block.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
||||
// Ensure that the block containing `EnterFunction` always comes first.
|
||||
if block.getFirstInstruction() instanceof EnterFunctionInstruction
|
||||
then sortOverride = 0
|
||||
else sortOverride = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
|
||||
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
|
||||
@@ -37,17 +53,14 @@ class IRBlockBase extends TIRBlock {
|
||||
exists(IRConfiguration::IRConfiguration config |
|
||||
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
|
||||
) and
|
||||
this =
|
||||
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
||||
funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and
|
||||
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
||||
// Ensure that the block containing `EnterFunction` always comes first.
|
||||
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
|
||||
then sortOverride = 0
|
||||
else sortOverride = 1
|
||||
|
|
||||
funcBlock order by sortOverride, sortKey1, sortKey2
|
||||
)
|
||||
exists(IRFunction func |
|
||||
this =
|
||||
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
||||
blockSortKeys(func, funcBlock, sortOverride, sortKey1, sortKey2)
|
||||
|
|
||||
funcBlock order by sortOverride, sortKey1, sortKey2
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,14 +116,14 @@ class Instruction extends Construction::TStageInstruction {
|
||||
|
||||
private int getLineRank() {
|
||||
this.shouldGenerateDumpStrings() and
|
||||
this =
|
||||
rank[result](Instruction instr |
|
||||
instr =
|
||||
getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(),
|
||||
this.getLocation().getStartLine())
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
exists(IRFunction enclosing, Language::File file, int line |
|
||||
this =
|
||||
rank[result](Instruction instr |
|
||||
instr = getAnInstructionAtLine(enclosing, file, line)
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -423,7 +423,12 @@ private module CachedForDebugging {
|
||||
cached
|
||||
predicate instructionHasSortKeys(Instruction instruction, int key1, int key2) {
|
||||
key1 = getInstructionTranslatedElement(instruction).getId() and
|
||||
getInstructionTag(instruction) =
|
||||
getInstructionTag(instruction) = tagByRank(key2)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private InstructionTag tagByRank(int key2) {
|
||||
result =
|
||||
rank[key2](InstructionTag tag, string tagId |
|
||||
tagId = getInstructionTagId(tag)
|
||||
|
|
||||
|
||||
@@ -8,6 +8,22 @@ private import internal.IRBlockImports as Imports
|
||||
import Imports::EdgeKind
|
||||
private import Cached
|
||||
|
||||
/**
|
||||
* Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the
|
||||
* sort keys of the block (derived from its first instruction)
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate blockSortKeys(
|
||||
IRFunction func, IRBlockBase block, int sortOverride, int sortKey1, int sortKey2
|
||||
) {
|
||||
block.getEnclosingIRFunction() = func and
|
||||
block.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
||||
// Ensure that the block containing `EnterFunction` always comes first.
|
||||
if block.getFirstInstruction() instanceof EnterFunctionInstruction
|
||||
then sortOverride = 0
|
||||
else sortOverride = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
|
||||
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
|
||||
@@ -37,17 +53,14 @@ class IRBlockBase extends TIRBlock {
|
||||
exists(IRConfiguration::IRConfiguration config |
|
||||
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
|
||||
) and
|
||||
this =
|
||||
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
||||
funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and
|
||||
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
||||
// Ensure that the block containing `EnterFunction` always comes first.
|
||||
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
|
||||
then sortOverride = 0
|
||||
else sortOverride = 1
|
||||
|
|
||||
funcBlock order by sortOverride, sortKey1, sortKey2
|
||||
)
|
||||
exists(IRFunction func |
|
||||
this =
|
||||
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
||||
blockSortKeys(func, funcBlock, sortOverride, sortKey1, sortKey2)
|
||||
|
|
||||
funcBlock order by sortOverride, sortKey1, sortKey2
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,14 +116,14 @@ class Instruction extends Construction::TStageInstruction {
|
||||
|
||||
private int getLineRank() {
|
||||
this.shouldGenerateDumpStrings() and
|
||||
this =
|
||||
rank[result](Instruction instr |
|
||||
instr =
|
||||
getAnInstructionAtLine(this.getEnclosingIRFunction(), this.getLocation().getFile(),
|
||||
this.getLocation().getStartLine())
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
exists(IRFunction enclosing, Language::File file, int line |
|
||||
this =
|
||||
rank[result](Instruction instr |
|
||||
instr = getAnInstructionAtLine(enclosing, file, line)
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,7 @@ private import RangeAnalysisUtils
|
||||
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
|
||||
* This class provides the range-analysis SSA logic.
|
||||
*/
|
||||
library class RangeSsa extends SsaHelper {
|
||||
class RangeSsa extends SsaHelper {
|
||||
RangeSsa() { this = 1 }
|
||||
|
||||
/**
|
||||
|
||||
@@ -284,10 +284,33 @@ private module Config implements ProductFlow::StateConfigSig {
|
||||
pointerAddInstructionHasBounds0(_, allocSink, sizeSink, sizeAddend)
|
||||
}
|
||||
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) {
|
||||
node = SizeBarrier::getABarrierNode(state)
|
||||
}
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node) {
|
||||
// Block flow from `*p` to `*(p + n)` when `n` is not `0`. This removes
|
||||
// false positives
|
||||
// when tracking the size of the allocation as an element of an array such
|
||||
// as:
|
||||
// ```
|
||||
// size_t* p = new size_t[n];
|
||||
// ...
|
||||
// p[0] = n;
|
||||
// int i = p[1];
|
||||
// p[i] = ...
|
||||
// ```
|
||||
// In the above case, this barrier blocks flow from the indirect node
|
||||
// for `p` to `p[1]`.
|
||||
exists(Operand operand, PointerAddInstruction add |
|
||||
node.(IndirectOperand).hasOperandAndIndirectionIndex(operand, _) and
|
||||
add.getLeftOperand() = operand and
|
||||
add.getRight().(ConstantInstruction).getValue() != "0"
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrierIn1(DataFlow::Node node) { isSourcePair(node, _, _, _) }
|
||||
|
||||
predicate isBarrierOut2(DataFlow::Node node) {
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
## 0.8.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
|
||||
in cases where a non-returning function is called.
|
||||
* The number of duplicated dataflow paths reported by queries has been significantly reduced.
|
||||
|
||||
## 0.7.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
* it should be moved before the dereference.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision high
|
||||
* @id cpp/redundant-null-check-simple
|
||||
* @tags reliability
|
||||
* correctness
|
||||
* security
|
||||
* external/cwe/cwe-476
|
||||
*/
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ private predicate annotatesAtPosition(SalPosition pos, DeclarationEntry d, File
|
||||
* A SAL element, that is, a SAL annotation or a declaration entry
|
||||
* that may have SAL annotations.
|
||||
*/
|
||||
library class SalElement extends Element {
|
||||
class SalElement extends Element {
|
||||
SalElement() {
|
||||
containsSalAnnotation(this.(DeclarationEntry).getFile()) or
|
||||
this instanceof SalAnnotation
|
||||
|
||||
@@ -13,15 +13,13 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Environment
|
||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
||||
import TaintedWithPath
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.IR
|
||||
import Flow::PathGraph
|
||||
|
||||
/** A call that prints its arguments to `stdout`. */
|
||||
class PrintStdoutCall extends FunctionCall {
|
||||
PrintStdoutCall() {
|
||||
this.getTarget().hasGlobalOrStdName("puts") or
|
||||
this.getTarget().hasGlobalOrStdName("printf")
|
||||
}
|
||||
PrintStdoutCall() { this.getTarget().hasGlobalOrStdName(["puts", "printf"]) }
|
||||
}
|
||||
|
||||
/** A read of the QUERY_STRING environment variable */
|
||||
@@ -29,19 +27,25 @@ class QueryString extends EnvironmentRead {
|
||||
QueryString() { this.getEnvironmentVariable() = "QUERY_STRING" }
|
||||
}
|
||||
|
||||
class Configuration extends TaintTrackingConfiguration {
|
||||
override predicate isSource(Expr source) { source instanceof QueryString }
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) { node.asIndirectExpr() instanceof QueryString }
|
||||
|
||||
override predicate isSink(Element tainted) {
|
||||
exists(PrintStdoutCall call | call.getAnArgument() = tainted)
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(PrintStdoutCall call | call.getAnArgument() = [node.asIndirectExpr(), node.asExpr()])
|
||||
}
|
||||
|
||||
override predicate isBarrier(Expr e) {
|
||||
super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
|
||||
or
|
||||
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
|
||||
}
|
||||
}
|
||||
|
||||
from QueryString query, Element printedArg, PathNode sourceNode, PathNode sinkNode
|
||||
where taintedWithPath(query, printedArg, sourceNode, sinkNode)
|
||||
select printedArg, sourceNode, sinkNode, "Cross-site scripting vulnerability due to $@.", query,
|
||||
"this query data"
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
from QueryString query, Flow::PathNode sourceNode, Flow::PathNode sinkNode
|
||||
where
|
||||
Flow::flowPath(sourceNode, sinkNode) and
|
||||
query = sourceNode.getNode().asIndirectExpr()
|
||||
select sinkNode.getNode(), sourceNode, sinkNode, "Cross-site scripting vulnerability due to $@.",
|
||||
query, "this query data"
|
||||
|
||||
@@ -82,36 +82,20 @@ module ValidState {
|
||||
* library will perform, and visit all the places where the size argument is modified.
|
||||
* 2. Once that dataflow traversal is done, we accumulate the offsets added at each places
|
||||
* where the offset is modified (see `validStateImpl`).
|
||||
*
|
||||
* Because we want to guarantee that each place where we modify the offset has a `PathNode`
|
||||
* we "flip" a boolean flow state in each `isAdditionalFlowStep`. This ensures that the node
|
||||
* has a corresponding `PathNode`.
|
||||
*/
|
||||
private module ValidStateConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState = boolean;
|
||||
private module ValidStateConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { hasSize(_, source, _) }
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
hasSize(_, source, _) and
|
||||
state = false
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { isSinkPairImpl(_, _, sink, _, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
isSinkPairImpl(_, _, sink, _, _) and
|
||||
state = [false, true]
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
isAdditionalFlowStep2(node1, node2, _) and
|
||||
state1 = [false, true] and
|
||||
state2 = state1.booleanNot()
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
isAdditionalFlowStep2(node1, node2, _)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any() }
|
||||
}
|
||||
|
||||
private import DataFlow::GlobalWithState<ValidStateConfig>
|
||||
private import DataFlow::Global<ValidStateConfig>
|
||||
|
||||
private predicate inLoop(PathNode n) { n.getASuccessor+() = n }
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The number of duplicated dataflow paths reported by queries has been significantly reduced.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
|
||||
in cases where a non-returning function is called.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* The query `cpp/redundant-null-check-simple` has been promoted to Code Scanning. The query finds cases where a pointer is compared to null after it has already been dereferenced. Such comparisons likely indicate a bug at the place where the pointer is dereferenced, or where the pointer is compared to null.
|
||||
|
||||
Note: This query was incorrectly noted as being promoted to Code Scanning in CodeQL version 2.14.6.
|
||||
12
cpp/ql/src/change-notes/released/0.8.0.md
Normal file
12
cpp/ql/src/change-notes/released/0.8.0.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## 0.8.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
|
||||
in cases where a non-returning function is called.
|
||||
* The number of duplicated dataflow paths reported by queries has been significantly reduced.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.5
|
||||
lastReleaseVersion: 0.8.0
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @name Unknown key generation key size
|
||||
* @description
|
||||
* @id cpp/unknown-asymmetric-key-gen-size
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags external/cwe/cwe-326
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from AsymmetricKeyGeneration op, AsymmetricAlgorithm alg
|
||||
where
|
||||
alg = op.getAlgorithm() and
|
||||
not alg instanceof EllipticCurveAlgorithm and
|
||||
not exists(op.getKeySizeInBits(alg))
|
||||
select op, "Use of unknown asymmetric key size for algorithm $@", alg, alg.getName().toString()
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @name Weak asymmetric key generation key size (< 2048 bits)
|
||||
* @description
|
||||
* @id cpp/weak-asymmetric-key-gen-size
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags external/cwe/cwe-326
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from AsymmetricKeyGeneration op, AsymmetricAlgorithm alg, Expr configSrc, int size
|
||||
where
|
||||
alg = op.getAlgorithm() and
|
||||
not alg instanceof EllipticCurveAlgorithm and
|
||||
configSrc = op.getKeyConfigurationSource(alg) and
|
||||
size = configSrc.getValue().toInt() and
|
||||
size < 2048
|
||||
select op,
|
||||
"Use of weak asymmetric key size (in bits) " + size + " configured at $@ for algorithm $@",
|
||||
configSrc, configSrc.toString(), alg, alg.getName().toString()
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @name Weak block mode
|
||||
* @description Finds uses of symmetric encryption block modes that are weak, obsolete, or otherwise unaccepted.
|
||||
* @id cpp/weak-block-mode
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags external/cwe/cwe-327
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from BlockModeAlgorithm alg, string name, string msg, Expr confSink
|
||||
where
|
||||
exists(string tmpMsg |
|
||||
(
|
||||
name = alg.getBlockModeName() and
|
||||
name = unknownAlgorithm() and
|
||||
tmpMsg = "Use of unrecognized block mode algorithm."
|
||||
or
|
||||
name != unknownAlgorithm() and
|
||||
name = alg.getBlockModeName() and
|
||||
not name = ["CBC", "CTS", "XTS"] and
|
||||
tmpMsg = "Use of weak block mode algorithm " + name + "."
|
||||
) and
|
||||
if alg.hasConfigurationSink() and alg.configurationSink() != alg
|
||||
then (
|
||||
confSink = alg.configurationSink() and msg = tmpMsg + " Algorithm used at sink: $@."
|
||||
) else (
|
||||
confSink = alg and msg = tmpMsg
|
||||
)
|
||||
)
|
||||
select alg, msg, confSink, confSink.toString()
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @name Weak elliptic curve
|
||||
* @description Finds uses of weak, unknown, or otherwise unaccepted elliptic curve algorithms.
|
||||
* @id cpp/weak-elliptic-curve
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags external/cwe/cwe-327
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from EllipticCurveAlgorithm alg, string name, string msg, Expr confSink
|
||||
where
|
||||
exists(string tmpMsg |
|
||||
(
|
||||
name = alg.getCurveName() and
|
||||
name = unknownAlgorithm() and
|
||||
tmpMsg = "Use of unrecognized curve algorithm."
|
||||
or
|
||||
name != unknownAlgorithm() and
|
||||
name = alg.getCurveName() and
|
||||
not name =
|
||||
[
|
||||
"SECP256R1", "PRIME256V1", //P-256
|
||||
"SECP384R1", //P-384
|
||||
"SECP521R1", //P-521
|
||||
"ED25519", "X25519"
|
||||
] and
|
||||
tmpMsg = "Use of weak curve algorithm " + name + "."
|
||||
) and
|
||||
if alg.hasConfigurationSink() and alg.configurationSink() != alg
|
||||
then (
|
||||
confSink = alg.configurationSink() and msg = tmpMsg + " Algorithm used at sink: $@."
|
||||
) else (
|
||||
confSink = alg and msg = tmpMsg
|
||||
)
|
||||
)
|
||||
select alg, msg, confSink, confSink.toString()
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @name Weak cryptography
|
||||
* @description Finds explicit uses of symmetric encryption algorithms that are weak, unknown, or otherwise unaccepted.
|
||||
* @kind problem
|
||||
* @id cpp/weak-crypto/banned-encryption-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags external/cwe/cwe-327
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from SymmetricEncryptionAlgorithm alg, Expr confSink, string msg
|
||||
where
|
||||
exists(string resMsg |
|
||||
(
|
||||
if alg.getEncryptionName() = unknownAlgorithm()
|
||||
then (
|
||||
alg instanceof Literal and
|
||||
resMsg =
|
||||
"Use of unrecognized symmetric encryption algorithm: " +
|
||||
alg.(Literal).getValueText().toString() + "."
|
||||
or
|
||||
not alg instanceof Literal and
|
||||
resMsg = "Use of unrecognized symmetric encryption algorithm."
|
||||
) else (
|
||||
not alg.getEncryptionName().matches("AES%") and
|
||||
resMsg = "Use of banned symmetric encryption algorithm: " + alg.getEncryptionName() + "."
|
||||
)
|
||||
) and
|
||||
(
|
||||
if alg.hasConfigurationSink() and alg.configurationSink() != alg
|
||||
then (
|
||||
confSink = alg.configurationSink() and msg = resMsg + " Algorithm used at sink: $@."
|
||||
) else (
|
||||
confSink = alg and msg = resMsg
|
||||
)
|
||||
)
|
||||
)
|
||||
select alg, msg, confSink, confSink.toString()
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @name Weak cryptography
|
||||
* @description Finds explicit uses of cryptographic hash algorithms that are weak and obsolete.
|
||||
* @kind problem
|
||||
* @id cpp/weak-crypto/banned-hash-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags external/cwe/cwe-327
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.DataFlow as ASTDataFlow
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from HashAlgorithm alg, Expr confSink, string msg
|
||||
where
|
||||
exists(string name, string msgTmp | name = alg.getHashName() |
|
||||
not name = ["SHA256", "SHA384", "SHA512"] and
|
||||
(
|
||||
if name = unknownAlgorithm()
|
||||
then
|
||||
not alg instanceof Literal and msgTmp = "Use of unrecognized hash algorithm."
|
||||
or
|
||||
alg instanceof Literal and
|
||||
msgTmp =
|
||||
"Use of unrecognized hash algorithm: " + alg.(Literal).getValueText().toString() + "."
|
||||
else msgTmp = "Use of banned hash algorithm " + name + "."
|
||||
) and
|
||||
if alg.hasConfigurationSink() and alg.configurationSink() != alg
|
||||
then (
|
||||
confSink = alg.configurationSink() and msg = msgTmp + " Algorithm used at sink: $@."
|
||||
) else (
|
||||
confSink = alg and msg = msgTmp
|
||||
)
|
||||
)
|
||||
select alg, msg, confSink, confSink.toString()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name All Asymmetric Algorithms
|
||||
* @description Finds all potential usage of asymmeric keys (RSA & ECC) using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/all-asymmetric-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from AsymmetricAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name All Cryptographic Algorithms
|
||||
* @description Finds all potential usage of cryptographic algorithms usage using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/all-cryptographic-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from CryptographicAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Asymmetric Encryption Algorithms
|
||||
* @description Finds all potential usage of asymmeric keys for encryption or key exchange using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/all-asymmetric-encryption-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from AsymmetricEncryptionAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getEncryptionName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Asymmetric Padding Schemes
|
||||
* @description Finds all potential usage of padding schemes used with asymmeric algorithms.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/asymmetric-padding-schemes
|
||||
* @problem.severity error
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
// TODO: currently not modeled for any API
|
||||
from AsymmetricPadding alg
|
||||
select alg, "Use of algorithm " + alg.getPaddingName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Authenticated Encryption Algorithms
|
||||
* @description Finds all potential usage of authenticated encryption schemes using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/authenticated-encryption-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from AuthenticatedEncryptionAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getAuthticatedEncryptionName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Block cipher mode of operation
|
||||
* @description Finds all potential block cipher modes of operations using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/block-cipher-mode
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from BlockModeAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getBlockModeName()
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name Initialization Vector (IV) or nonces
|
||||
* @description Finds all potential sources for initialization vectors (IV) or nonce used in block ciphers while using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/iv-sources
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
// TODO: currently not modeled for any API
|
||||
from BlockModeAlgorithm alg
|
||||
select alg.getIVorNonce(), "Block mode IV/Nonce source"
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @name Unknown Initialization Vector (IV) or nonces
|
||||
* @description Finds all potentially unknown sources for initialization vectors (IV) or nonce used in block ciphers while using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/unkown-iv-sources
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
// TODO: currently not modeled for any API
|
||||
from BlockModeAlgorithm alg
|
||||
where not alg.hasIVorNonce()
|
||||
select alg, "Block mode with unknown IV or Nonce configuration"
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @name Elliptic Curve Key length
|
||||
* @description Finds all potential key lengths for elliptic curve algorithms usage.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/elliptic-curve-key-length
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from EllipticCurveAlgorithm alg, string size
|
||||
where
|
||||
if not exists(alg.getCurveBitSize())
|
||||
then size = "UNKNOWN SIZE"
|
||||
else size = alg.getCurveBitSize().toString()
|
||||
select alg, "Use of algorithm " + alg.getCurveName() + " with key size (in bits) " + size
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Elliptic Curve Algorithms
|
||||
* @description Finds all potential usage of elliptic curve algorithms using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/elliptic-curve-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from EllipticCurveAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getCurveName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Hash Algorithms
|
||||
* @description Finds all potential usage of cryptographic hash algorithms using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/hash-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from HashAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Key Exchange Algorithms
|
||||
* @description Finds all potential usage of key exchange using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/key-exchange
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from KeyExchangeAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getName()
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @name Known asymmetric key source generation
|
||||
* @description Finds all known potential sources for asymmetric key generation while using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/asymmetric-key-generation
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from AsymmetricKeyGeneration op, CryptographicAlgorithm alg, Expr configSrc
|
||||
where
|
||||
alg = op.getAlgorithm() and
|
||||
configSrc = op.getKeyConfigurationSource(alg)
|
||||
select op, "Key generator for algorithm $@ with key configuration $@", alg, alg.getName(),
|
||||
configSrc, configSrc.toString()
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name Signing Algorithms
|
||||
* @description Finds all potential usage of signing algorithms using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/signing-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
// TODO: currently not modeled for any API
|
||||
from SigningAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Symmetric Encryption Algorithms
|
||||
* @description Finds all potential usage of symmetric encryption algorithms using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/symmetric-encryption-algorithms
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from SymmetricEncryptionAlgorithm alg
|
||||
select alg, "Use of algorithm " + alg.getEncryptionName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Symmetric Padding Schemes
|
||||
* @description Finds all potential usage of padding schemes used with symmeric algorithms.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/symmetric-padding-schemes
|
||||
* @problem.severity error
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
// TODO: currently not modeled for any API
|
||||
from SymmetricPadding alg
|
||||
select alg, "Use of algorithm " + alg.getPaddingName()
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @name Unknown asymmetric key source generation
|
||||
* @description Finds all unknown potential sources for asymmetric key generation while using the supported libraries.
|
||||
* @kind problem
|
||||
* @id cpp/quantum-readiness/cbom/unkwon-asymmetric-key-generation
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags cbom
|
||||
* cryptography
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.cryptography.Concepts
|
||||
|
||||
from AsymmetricKeyGeneration op, CryptographicAlgorithm alg
|
||||
where
|
||||
alg = op.getAlgorithm() and
|
||||
not op.hasKeyConfigurationSource(alg)
|
||||
select op, "Key generator for algorithm $@ with unknown configuration source", alg, alg.getName()
|
||||
@@ -0,0 +1 @@
|
||||
No existing 'old models' for inventories
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.8.0-dev
|
||||
version: 0.8.1-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -36,6 +36,8 @@ edges
|
||||
| test.cpp:143:18:143:21 | asdf | test.cpp:134:25:134:27 | arr |
|
||||
| test.cpp:143:18:143:21 | asdf | test.cpp:143:18:143:21 | asdf |
|
||||
| test.cpp:146:26:146:26 | p indirection | test.cpp:148:6:148:9 | * ... |
|
||||
| test.cpp:146:26:146:26 | p indirection | test.cpp:149:6:149:9 | * ... |
|
||||
| test.cpp:146:26:146:26 | p indirection | test.cpp:150:6:150:9 | * ... |
|
||||
| test.cpp:156:12:156:14 | buf | test.cpp:156:12:156:18 | ... + ... |
|
||||
| test.cpp:156:12:156:18 | ... + ... | test.cpp:158:17:158:18 | & ... indirection |
|
||||
| test.cpp:158:17:158:18 | & ... indirection | test.cpp:146:26:146:26 | p indirection |
|
||||
@@ -123,6 +125,8 @@ nodes
|
||||
| test.cpp:143:18:143:21 | asdf | semmle.label | asdf |
|
||||
| test.cpp:146:26:146:26 | p indirection | semmle.label | p indirection |
|
||||
| test.cpp:148:6:148:9 | * ... | semmle.label | * ... |
|
||||
| test.cpp:149:6:149:9 | * ... | semmle.label | * ... |
|
||||
| test.cpp:150:6:150:9 | * ... | semmle.label | * ... |
|
||||
| test.cpp:156:12:156:14 | buf | semmle.label | buf |
|
||||
| test.cpp:156:12:156:18 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:158:17:158:18 | & ... indirection | semmle.label | & ... indirection |
|
||||
@@ -176,6 +180,8 @@ subpaths
|
||||
| test.cpp:128:9:128:14 | PointerAdd: access to array | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:125:11:125:13 | arr | arr | test.cpp:128:9:128:18 | Store: ... = ... | write |
|
||||
| test.cpp:136:9:136:16 | PointerAdd: ... += ... | test.cpp:143:18:143:21 | asdf | test.cpp:138:13:138:15 | arr | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:142:10:142:13 | asdf | asdf | test.cpp:138:12:138:15 | Load: * ... | read |
|
||||
| test.cpp:156:12:156:18 | PointerAdd: ... + ... | test.cpp:156:12:156:14 | buf | test.cpp:148:6:148:9 | * ... | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:154:7:154:9 | buf | buf | test.cpp:147:3:147:13 | Store: ... = ... | write |
|
||||
| test.cpp:156:12:156:18 | PointerAdd: ... + ... | test.cpp:156:12:156:14 | buf | test.cpp:149:6:149:9 | * ... | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:154:7:154:9 | buf | buf | test.cpp:148:3:148:13 | Store: ... = ... | write |
|
||||
| test.cpp:156:12:156:18 | PointerAdd: ... + ... | test.cpp:156:12:156:14 | buf | test.cpp:150:6:150:9 | * ... | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:154:7:154:9 | buf | buf | test.cpp:149:3:149:13 | Store: ... = ... | write |
|
||||
| test.cpp:221:5:221:11 | PointerAdd: access to array | test.cpp:218:23:218:28 | buffer | test.cpp:221:5:221:11 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:217:19:217:24 | buffer | buffer | test.cpp:221:5:221:15 | Store: ... = ... | write |
|
||||
| test.cpp:232:5:232:10 | PointerAdd: access to array | test.cpp:229:25:229:29 | array | test.cpp:232:5:232:10 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:228:10:228:14 | array | array | test.cpp:232:5:232:19 | Store: ... = ... | write |
|
||||
| test.cpp:261:27:261:30 | PointerAdd: access to array | test.cpp:286:19:286:25 | buffer2 | test.cpp:261:27:261:30 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:285:19:285:25 | buffer2 | buffer2 | test.cpp:261:27:261:30 | Load: access to array | read |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
failures
|
||||
astTypeBugs
|
||||
irTypeBugs
|
||||
failures
|
||||
|
||||
@@ -16,18 +16,18 @@ edges
|
||||
| test.cpp:91:9:91:16 | fread output argument | test.cpp:93:17:93:24 | filename indirection |
|
||||
| test.cpp:93:11:93:14 | strncat output argument | test.cpp:94:45:94:48 | path indirection |
|
||||
| test.cpp:93:17:93:24 | filename indirection | test.cpp:93:11:93:14 | strncat output argument |
|
||||
| test.cpp:106:20:106:25 | call to getenv | test.cpp:107:33:107:36 | path indirection |
|
||||
| test.cpp:106:20:106:38 | call to getenv | test.cpp:107:33:107:36 | path indirection |
|
||||
| test.cpp:106:20:106:38 | call to getenv indirection | test.cpp:107:33:107:36 | path indirection |
|
||||
| test.cpp:107:31:107:31 | call to operator+ | test.cpp:108:18:108:22 | call to c_str indirection |
|
||||
| test.cpp:107:33:107:36 | path indirection | test.cpp:107:31:107:31 | call to operator+ |
|
||||
| test.cpp:113:20:113:25 | call to getenv | test.cpp:114:19:114:22 | path indirection |
|
||||
| test.cpp:113:20:113:38 | call to getenv | test.cpp:114:19:114:22 | path indirection |
|
||||
| test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:19:114:22 | path indirection |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
|
||||
| test.cpp:114:17:114:17 | call to operator+ | test.cpp:114:10:114:23 | call to operator+ |
|
||||
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:10:114:23 | call to operator+ |
|
||||
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | call to operator+ |
|
||||
| test.cpp:119:20:119:25 | call to getenv | test.cpp:120:19:120:22 | path indirection |
|
||||
| test.cpp:119:20:119:38 | call to getenv | test.cpp:120:19:120:22 | path indirection |
|
||||
| test.cpp:119:20:119:38 | call to getenv indirection | test.cpp:120:19:120:22 | path indirection |
|
||||
| test.cpp:120:17:120:17 | call to operator+ | test.cpp:120:10:120:30 | call to data indirection |
|
||||
| test.cpp:120:19:120:22 | path indirection | test.cpp:120:17:120:17 | call to operator+ |
|
||||
@@ -91,12 +91,12 @@ nodes
|
||||
| test.cpp:93:11:93:14 | strncat output argument | semmle.label | strncat output argument |
|
||||
| test.cpp:93:17:93:24 | filename indirection | semmle.label | filename indirection |
|
||||
| test.cpp:94:45:94:48 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:106:20:106:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:106:20:106:38 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:106:20:106:38 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:107:31:107:31 | call to operator+ | semmle.label | call to operator+ |
|
||||
| test.cpp:107:33:107:36 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:108:18:108:22 | call to c_str indirection | semmle.label | call to c_str indirection |
|
||||
| test.cpp:113:20:113:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:113:20:113:38 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:113:20:113:38 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
|
||||
@@ -104,7 +104,7 @@ nodes
|
||||
| test.cpp:114:19:114:22 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:114:25:114:29 | call to c_str indirection | semmle.label | call to c_str indirection |
|
||||
| test.cpp:114:25:114:29 | call to c_str indirection | semmle.label | call to c_str indirection |
|
||||
| test.cpp:119:20:119:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:119:20:119:38 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:119:20:119:38 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:120:10:120:30 | call to data indirection | semmle.label | call to data indirection |
|
||||
| test.cpp:120:17:120:17 | call to operator+ | semmle.label | call to operator+ |
|
||||
@@ -158,13 +158,13 @@ subpaths
|
||||
| test.cpp:65:10:65:16 | command | test.cpp:62:9:62:16 | fread output argument | test.cpp:65:10:65:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:62:9:62:16 | fread output argument | user input (string read by fread) | test.cpp:64:11:64:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:85:32:85:38 | command | test.cpp:82:9:82:16 | fread output argument | test.cpp:85:32:85:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:82:9:82:16 | fread output argument | user input (string read by fread) | test.cpp:84:11:84:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:94:45:94:48 | path | test.cpp:91:9:91:16 | fread output argument | test.cpp:94:45:94:48 | path indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:91:9:91:16 | fread output argument | user input (string read by fread) | test.cpp:93:11:93:14 | strncat output argument | strncat output argument |
|
||||
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:25 | call to getenv | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:25 | call to getenv | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
|
||||
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:38 | call to getenv | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:38 | call to getenv | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
|
||||
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:38 | call to getenv indirection | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:38 | call to getenv indirection | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv indirection | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv indirection | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:25 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:25 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:38 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:38 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:38 | call to getenv indirection | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:38 | call to getenv indirection | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:143:10:143:16 | command | test.cpp:140:9:140:11 | fread output argument | test.cpp:143:10:143:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:140:9:140:11 | fread output argument | user input (string read by fread) | test.cpp:142:11:142:17 | sprintf output argument | sprintf output argument |
|
||||
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (string read by fread) | test.cpp:177:13:177:17 | strncat output argument | strncat output argument |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user