mirror of
https://github.com/github/codeql.git
synced 2026-05-26 17:11:24 +02:00
Compare commits
1 Commits
esteffin/r
...
idrissrio/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fac2beac13 |
4
.github/copilot-instructions.md
vendored
Normal file
4
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
When reviewing code:
|
||||
* do not review changes in files with `.expected` extension (they are automatically ensured to be correct).
|
||||
* in `.ql` and `.qll` files, do not try to review the code itself as you don't understand the programming language
|
||||
well enough to make comments in these languages. You can still check for typos or comment improvements.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
applyTo: "**/*.expected"
|
||||
---
|
||||
Ignore these files. These are generated to be correct by running the tests, and should not be edited manually.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
applyTo: "**/*.ql,**/*.qll"
|
||||
---
|
||||
When reviewing these QL files, do not make any comment on the code itself. You don't understand the QL programming language well enough yet. You can only make comments about the following aspects:
|
||||
* comments (lines starting with `//` or block comments enclosed in `/* ... */`): you can suggest improvements to the clarity of comments, or point out spelling mistakes
|
||||
* typos in identifiers
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.300
|
||||
dotnet-version: 9.0.100
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
10
.github/workflows/csharp-qltest.yml
vendored
10
.github/workflows/csharp-qltest.yml
vendored
@@ -43,14 +43,14 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.300
|
||||
dotnet-version: 9.0.100
|
||||
- name: Extractor unit tests
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
shell: bash
|
||||
stubgentest:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -76,6 +76,3 @@ node_modules/
|
||||
# some upgrade/downgrade checks create these files
|
||||
**/upgrades/*/*.dbscheme.stats
|
||||
**/downgrades/*/*.dbscheme.stats
|
||||
|
||||
# Mergetool files
|
||||
*.orig
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# Catch-all for anything which isn't matched by a line lower down
|
||||
* @github/code-scanning-alert-coverage
|
||||
|
||||
# CodeQL language libraries
|
||||
/actions/ @github/codeql-dynamic
|
||||
/cpp/ @github/codeql-c-analysis
|
||||
/csharp/ @github/codeql-csharp
|
||||
@@ -11,10 +7,8 @@
|
||||
/java/ @github/codeql-java
|
||||
/javascript/ @github/codeql-javascript
|
||||
/python/ @github/codeql-python
|
||||
/ql/ @github/codeql-ql-for-ql-reviewers
|
||||
/ruby/ @github/codeql-ruby
|
||||
/rust/ @github/codeql-rust
|
||||
/shared/ @github/codeql-shared-libraries-reviewers
|
||||
/swift/ @github/codeql-swift
|
||||
/misc/codegen/ @github/codeql-swift
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||
@@ -31,6 +25,9 @@
|
||||
/docs/codeql/ql-language-reference/ @github/codeql-frontend-reviewers
|
||||
/docs/query-*-style-guide.md @github/codeql-analysis-reviewers
|
||||
|
||||
# QL for QL reviewers
|
||||
/ql/ @github/codeql-ql-for-ql-reviewers
|
||||
|
||||
# Bazel (excluding BUILD.bazel files)
|
||||
MODULE.bazel @github/codeql-ci-reviewers
|
||||
.bazelversion @github/codeql-ci-reviewers
|
||||
|
||||
763
Cargo.lock
generated
763
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -10,3 +10,4 @@ members = [
|
||||
"rust/ast-generator",
|
||||
"rust/autobuild",
|
||||
]
|
||||
exclude = ["mad-generation-build"]
|
||||
|
||||
80
MODULE.bazel
80
MODULE.bazel
@@ -19,16 +19,16 @@ bazel_dep(name = "rules_go", version = "0.56.1")
|
||||
bazel_dep(name = "rules_pkg", version = "1.0.1")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
|
||||
bazel_dep(name = "rules_python", version = "0.40.0")
|
||||
bazel_dep(name = "rules_shell", version = "0.5.0")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.8.1")
|
||||
bazel_dep(name = "rules_shell", version = "0.3.0")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.7.1")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.1.3-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.40.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.19.2-codeql.1")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.17.4")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.66.0")
|
||||
bazel_dep(name = "rules_rust", version = "0.63.0")
|
||||
bazel_dep(name = "zstd", version = "1.5.5.bcr.1")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
@@ -89,8 +89,8 @@ use_repo(
|
||||
"vendor_py__cc-1.2.14",
|
||||
"vendor_py__clap-4.5.30",
|
||||
"vendor_py__regex-1.11.1",
|
||||
"vendor_py__tree-sitter-0.24.7",
|
||||
"vendor_py__tree-sitter-graph-0.12.0",
|
||||
"vendor_py__tree-sitter-0.20.4",
|
||||
"vendor_py__tree-sitter-graph-0.7.0",
|
||||
)
|
||||
|
||||
# deps for ruby+rust
|
||||
@@ -98,54 +98,54 @@ use_repo(
|
||||
tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r")
|
||||
use_repo(
|
||||
tree_sitter_extractors_deps,
|
||||
"vendor_ts__anyhow-1.0.100",
|
||||
"vendor_ts__anyhow-1.0.99",
|
||||
"vendor_ts__argfile-0.2.1",
|
||||
"vendor_ts__chalk-ir-0.104.0",
|
||||
"vendor_ts__chrono-0.4.42",
|
||||
"vendor_ts__clap-4.5.48",
|
||||
"vendor_ts__chrono-0.4.41",
|
||||
"vendor_ts__clap-4.5.44",
|
||||
"vendor_ts__dunce-1.0.5",
|
||||
"vendor_ts__either-1.15.0",
|
||||
"vendor_ts__encoding-0.2.33",
|
||||
"vendor_ts__figment-0.10.19",
|
||||
"vendor_ts__flate2-1.1.2",
|
||||
"vendor_ts__flate2-1.1.0",
|
||||
"vendor_ts__glob-0.3.3",
|
||||
"vendor_ts__globset-0.4.16",
|
||||
"vendor_ts__globset-0.4.15",
|
||||
"vendor_ts__itertools-0.14.0",
|
||||
"vendor_ts__lazy_static-1.5.0",
|
||||
"vendor_ts__mustache-0.9.0",
|
||||
"vendor_ts__num-traits-0.2.19",
|
||||
"vendor_ts__num_cpus-1.17.0",
|
||||
"vendor_ts__proc-macro2-1.0.101",
|
||||
"vendor_ts__quote-1.0.41",
|
||||
"vendor_ts__ra_ap_base_db-0.0.301",
|
||||
"vendor_ts__ra_ap_cfg-0.0.301",
|
||||
"vendor_ts__ra_ap_hir-0.0.301",
|
||||
"vendor_ts__ra_ap_hir_def-0.0.301",
|
||||
"vendor_ts__ra_ap_hir_expand-0.0.301",
|
||||
"vendor_ts__ra_ap_hir_ty-0.0.301",
|
||||
"vendor_ts__ra_ap_ide_db-0.0.301",
|
||||
"vendor_ts__ra_ap_intern-0.0.301",
|
||||
"vendor_ts__ra_ap_load-cargo-0.0.301",
|
||||
"vendor_ts__ra_ap_parser-0.0.301",
|
||||
"vendor_ts__ra_ap_paths-0.0.301",
|
||||
"vendor_ts__ra_ap_project_model-0.0.301",
|
||||
"vendor_ts__ra_ap_span-0.0.301",
|
||||
"vendor_ts__ra_ap_stdx-0.0.301",
|
||||
"vendor_ts__ra_ap_syntax-0.0.301",
|
||||
"vendor_ts__ra_ap_vfs-0.0.301",
|
||||
"vendor_ts__proc-macro2-1.0.97",
|
||||
"vendor_ts__quote-1.0.40",
|
||||
"vendor_ts__ra_ap_base_db-0.0.300",
|
||||
"vendor_ts__ra_ap_cfg-0.0.300",
|
||||
"vendor_ts__ra_ap_hir-0.0.300",
|
||||
"vendor_ts__ra_ap_hir_def-0.0.300",
|
||||
"vendor_ts__ra_ap_hir_expand-0.0.300",
|
||||
"vendor_ts__ra_ap_hir_ty-0.0.300",
|
||||
"vendor_ts__ra_ap_ide_db-0.0.300",
|
||||
"vendor_ts__ra_ap_intern-0.0.300",
|
||||
"vendor_ts__ra_ap_load-cargo-0.0.300",
|
||||
"vendor_ts__ra_ap_parser-0.0.300",
|
||||
"vendor_ts__ra_ap_paths-0.0.300",
|
||||
"vendor_ts__ra_ap_project_model-0.0.300",
|
||||
"vendor_ts__ra_ap_span-0.0.300",
|
||||
"vendor_ts__ra_ap_stdx-0.0.300",
|
||||
"vendor_ts__ra_ap_syntax-0.0.300",
|
||||
"vendor_ts__ra_ap_vfs-0.0.300",
|
||||
"vendor_ts__rand-0.9.2",
|
||||
"vendor_ts__rayon-1.11.0",
|
||||
"vendor_ts__regex-1.11.3",
|
||||
"vendor_ts__serde-1.0.228",
|
||||
"vendor_ts__serde_json-1.0.145",
|
||||
"vendor_ts__serde_with-3.14.1",
|
||||
"vendor_ts__syn-2.0.106",
|
||||
"vendor_ts__toml-0.9.7",
|
||||
"vendor_ts__rayon-1.10.0",
|
||||
"vendor_ts__regex-1.11.1",
|
||||
"vendor_ts__serde-1.0.219",
|
||||
"vendor_ts__serde_json-1.0.142",
|
||||
"vendor_ts__serde_with-3.14.0",
|
||||
"vendor_ts__syn-2.0.104",
|
||||
"vendor_ts__toml-0.9.5",
|
||||
"vendor_ts__tracing-0.1.41",
|
||||
"vendor_ts__tracing-flame-0.2.0",
|
||||
"vendor_ts__tracing-subscriber-0.3.20",
|
||||
"vendor_ts__tree-sitter-0.25.9",
|
||||
"vendor_ts__tree-sitter-embedded-template-0.25.0",
|
||||
"vendor_ts__tracing-subscriber-0.3.19",
|
||||
"vendor_ts__tree-sitter-0.24.6",
|
||||
"vendor_ts__tree-sitter-embedded-template-0.23.2",
|
||||
"vendor_ts__tree-sitter-json-0.24.8",
|
||||
"vendor_ts__tree-sitter-ql-0.23.1",
|
||||
"vendor_ts__tree-sitter-ruby-0.23.1",
|
||||
@@ -172,7 +172,7 @@ http_archive(
|
||||
)
|
||||
|
||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||
dotnet.toolchain(dotnet_version = "9.0.300")
|
||||
dotnet.toolchain(dotnet_version = "9.0.100")
|
||||
use_repo(dotnet, "dotnet_toolchains")
|
||||
|
||||
register_toolchains("@dotnet_toolchains//:all")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
name: "actions"
|
||||
aliases: []
|
||||
display_name: "GitHub Actions"
|
||||
version: 0.0.1
|
||||
column_kind: "utf16"
|
||||
@@ -7,11 +8,9 @@ build_modes:
|
||||
- none
|
||||
default_queries:
|
||||
- codeql/actions-queries
|
||||
# Actions workflows are not reported separately by the GitHub API, so we can't
|
||||
# associate them with a specific language.
|
||||
file_coverage_languages: []
|
||||
github_api_languages: []
|
||||
scc_languages:
|
||||
- YAML
|
||||
scc_languages: []
|
||||
file_types:
|
||||
- name: workflow
|
||||
display_name: GitHub Actions workflow files
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"paths": [
|
||||
".github/workflows/*.yml",
|
||||
".github/workflows/*.yaml",
|
||||
".github/reusable_workflows/**/*.yml",
|
||||
".github/reusable_workflows/**/*.yaml",
|
||||
"**/action.yml",
|
||||
"**/action.yaml"
|
||||
]
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
type "%CODEQL_EXTRACTOR_ACTIONS_ROOT%\tools\baseline-config.json"
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat "$CODEQL_EXTRACTOR_ACTIONS_ROOT/tools/baseline-config.json"
|
||||
@@ -1,4 +1,3 @@
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-094/CodeInjectionCritical.ql
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
ql/actions/ql/src/Debug/SyntaxError.ql
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionMedium.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionMedium.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
## 0.4.20
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.19
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.18
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.17
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.16
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.17
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.18
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.19
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.20
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.20
|
||||
lastReleaseVersion: 0.4.16
|
||||
|
||||
@@ -100,6 +100,8 @@ private module ArgumentInjectionConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
|
||||
@@ -333,6 +333,8 @@ private module ArtifactPoisoningConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
|
||||
@@ -80,6 +80,8 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
|
||||
@@ -130,6 +130,8 @@ private module EnvPathInjectionConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
|
||||
@@ -184,6 +184,8 @@ private module EnvVarInjectionConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
|
||||
@@ -212,6 +212,8 @@ private module OutputClobberingConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate an environment variable. */
|
||||
|
||||
@@ -18,6 +18,8 @@ private module RequestForgeryConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate a system command. */
|
||||
|
||||
@@ -17,6 +17,8 @@ private module SecretExfiltrationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SecretExfiltrationSink }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used in a context where it may lead to a secret exfiltration. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.21-dev
|
||||
version: 0.4.17-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,21 +1,3 @@
|
||||
## 0.6.12
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.11
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.10
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Actions analysis now reports file coverage information on the CodeQL status page.
|
||||
|
||||
## 0.6.8
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* @id actions/diagnostics/successfully-extracted-files
|
||||
* @name Extracted files
|
||||
* @description List all files that were extracted.
|
||||
* @kind diagnostic
|
||||
* @tags successfully-extracted-files
|
||||
*/
|
||||
|
||||
private import codeql.Locations
|
||||
|
||||
from File f
|
||||
where exists(f.getRelativePath())
|
||||
select f, ""
|
||||
@@ -26,6 +26,8 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -36,6 +36,8 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -27,6 +27,8 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -26,6 +26,8 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -36,6 +36,8 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -27,6 +27,8 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.10
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.11
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.12
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.6.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Actions analysis now reports file coverage information on the CodeQL status page.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.12
|
||||
lastReleaseVersion: 0.6.8
|
||||
|
||||
@@ -19,5 +19,5 @@ import SecretExfiltrationFlow::PathGraph
|
||||
from SecretExfiltrationFlow::PathNode source, SecretExfiltrationFlow::PathNode sink
|
||||
where SecretExfiltrationFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential secret exfiltration in $@, which may be leaked to an attacker-controlled resource.",
|
||||
"Potential secret exfiltration in $@, which may be be leaked to an attacker-controlled resource.",
|
||||
sink, sink.getNode().asExpr().(Expression).getRawExpression()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.13-dev
|
||||
version: 0.6.9-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -3,4 +3,4 @@ nodes
|
||||
| .github/workflows/test1.yml:15:11:16:75 | github.event.pull_request.title | semmle.label | github.event.pull_request.title |
|
||||
subpaths
|
||||
#select
|
||||
| .github/workflows/test1.yml:15:11:16:75 | github.event.pull_request.title | .github/workflows/test1.yml:15:11:16:75 | github.event.pull_request.title | .github/workflows/test1.yml:15:11:16:75 | github.event.pull_request.title | Potential secret exfiltration in $@, which may be leaked to an attacker-controlled resource. | .github/workflows/test1.yml:15:11:16:75 | github.event.pull_request.title | ${{ github.event.pull_request.title }} |
|
||||
| .github/workflows/test1.yml:15:11:16:75 | github.event.pull_request.title | .github/workflows/test1.yml:15:11:16:75 | github.event.pull_request.title | .github/workflows/test1.yml:15:11:16:75 | github.event.pull_request.title | Potential secret exfiltration in $@, which may be be leaked to an attacker-controlled resource. | .github/workflows/test1.yml:15:11:16:75 | github.event.pull_request.title | ${{ github.event.pull_request.title }} |
|
||||
|
||||
@@ -177,12 +177,6 @@ def insert_overlay_caller_annotations(lines):
|
||||
out_lines.append(line)
|
||||
return out_lines
|
||||
|
||||
explicitly_global = set([
|
||||
"java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll",
|
||||
"java/ql/lib/semmle/code/java/dispatch/DispatchFlow.qll",
|
||||
"java/ql/lib/semmle/code/java/dispatch/ObjFlow.qll",
|
||||
"java/ql/lib/semmle/code/java/dispatch/internal/Unification.qll",
|
||||
])
|
||||
|
||||
def annotate_as_appropriate(filename, lines):
|
||||
'''
|
||||
@@ -202,9 +196,6 @@ def annotate_as_appropriate(filename, lines):
|
||||
((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and
|
||||
any("implements DataFlow::ConfigSig" in line for line in lines))):
|
||||
return None
|
||||
elif filename in explicitly_global:
|
||||
# These files are explicitly global and should not be annotated.
|
||||
return None
|
||||
elif not any(line for line in lines if line.strip()):
|
||||
return None
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"fragments": [
|
||||
"/*- Compilations -*/",
|
||||
"/*- External data -*/",
|
||||
"/*- Overlay support -*/",
|
||||
"/*- Files and folders -*/",
|
||||
"/*- Diagnostic messages -*/",
|
||||
"/*- Diagnostic messages: severity -*/",
|
||||
|
||||
@@ -7,10 +7,12 @@ ql/cpp/ql/src/Diagnostics/ExtractedFiles.ql
|
||||
ql/cpp/ql/src/Diagnostics/ExtractionWarnings.ql
|
||||
ql/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
|
||||
@@ -28,6 +30,7 @@ ql/cpp/ql/src/Security/CWE/CWE-120/VeryLikelyOverrunWrite.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
|
||||
@@ -40,6 +43,7 @@ ql/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfUniquePointerAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-611/XXE.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql
|
||||
|
||||
@@ -1,31 +1,3 @@
|
||||
## 6.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 6.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The "Guards" libraries (`semmle.code.cpp.controlflow.Guards` and `semmle.code.cpp.controlflow.IRGuards`) have been totally rewritten to recognize many more guards. The API remains unchanged, but the `GuardCondition` class now extends `Element` instead of `Expr`.
|
||||
|
||||
### New Features
|
||||
|
||||
* C/C++ `build-mode: none` support is now generally available.
|
||||
|
||||
## 5.6.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 5.6.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The predicate `getAContructorCall` in the class `SslContextClass` has been deprecated. Use `getAConstructorCall` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type is defined in terms of another `VlaDeclStmt` via a `typedef`.
|
||||
|
||||
## 5.5.0
|
||||
|
||||
### New Features
|
||||
|
||||
4
cpp/ql/lib/change-notes/2025-09-02-vla.md
Normal file
4
cpp/ql/lib/change-notes/2025-09-02-vla.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type defined in terms of an other `VlaDeclStmt` via a `typedef`.
|
||||
4
cpp/ql/lib/change-notes/2025-09-03-rename-api.md
Normal file
4
cpp/ql/lib/change-notes/2025-09-03-rename-api.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The predicate `getAContructorCall` in the class `SslContextClass` has been deprecated. Use `getAConstructorCall` instead.
|
||||
@@ -1,9 +0,0 @@
|
||||
## 5.6.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The predicate `getAContructorCall` in the class `SslContextClass` has been deprecated. Use `getAConstructorCall` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type is defined in terms of another `VlaDeclStmt` via a `typedef`.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 5.6.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,9 +0,0 @@
|
||||
## 6.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The "Guards" libraries (`semmle.code.cpp.controlflow.Guards` and `semmle.code.cpp.controlflow.IRGuards`) have been totally rewritten to recognize many more guards. The API remains unchanged, but the `GuardCondition` class now extends `Element` instead of `Expr`.
|
||||
|
||||
### New Features
|
||||
|
||||
* C/C++ `build-mode: none` support is now generally available.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 6.0.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 6.0.1
|
||||
lastReleaseVersion: 5.5.0
|
||||
|
||||
@@ -14,8 +14,8 @@ module CryptoInput implements InputSig<Language::Location> {
|
||||
result = node.asExpr() or
|
||||
result = node.asParameter() or
|
||||
result = node.asVariable() or
|
||||
result = node.asDefiningArgument() or
|
||||
result = node.asIndirectExpr()
|
||||
result = node.asDefiningArgument()
|
||||
// TODO: do we need asIndirectExpr()?
|
||||
}
|
||||
|
||||
string locationToFileBaseNameAndLineNumberString(Location location) {
|
||||
@@ -53,7 +53,7 @@ module ArtifactFlowConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
}
|
||||
|
||||
module ArtifactFlow = TaintTracking::Global<ArtifactFlowConfig>;
|
||||
module ArtifactFlow = DataFlow::Global<ArtifactFlowConfig>;
|
||||
|
||||
/**
|
||||
* An artifact output to node input configuration
|
||||
@@ -93,13 +93,7 @@ module GenericDataSourceFlow = TaintTracking::Global<GenericDataSourceFlowConfig
|
||||
|
||||
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof OpenSslGenericSourceCandidateLiteral
|
||||
{
|
||||
override DataFlow::Node getOutputNode() {
|
||||
// OpenSSL algorithms may be referenced either by string name or by numeric ID:
|
||||
// String names (e.g. "AES-256-CBC") appear in the AST as character pointer
|
||||
// literals. For these we must use `asIndirectExpr`. Numeric IDs (e.g. NID_aes_256_cbc)
|
||||
// appear as integer literals. For these, we must use `asExpr` to get the "value" node.
|
||||
[result.asIndirectExpr(), result.asExpr()] = this
|
||||
}
|
||||
override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
// TODO: separate config to avoid blowing up data-flow analysis
|
||||
@@ -109,4 +103,28 @@ private class ConstantDataSource extends Crypto::GenericConstantSourceInstance i
|
||||
override string getAdditionalDescription() { result = this.toString() }
|
||||
}
|
||||
|
||||
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::ArtifactInstance artifact).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(Crypto::FlowAwareElement other).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
}
|
||||
}
|
||||
|
||||
module ArtifactUniversalFlow = DataFlow::Global<ArtifactUniversalFlowConfig>;
|
||||
|
||||
import OpenSSL.OpenSSL
|
||||
|
||||
@@ -14,13 +14,9 @@ private import PaddingAlgorithmInstance
|
||||
*/
|
||||
module KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
(
|
||||
source.asExpr() instanceof KnownOpenSslAlgorithmExpr or
|
||||
source.asIndirectExpr() instanceof KnownOpenSslAlgorithmExpr
|
||||
) and
|
||||
source.asExpr() instanceof KnownOpenSslAlgorithmExpr and
|
||||
// No need to flow direct operations to AVCs
|
||||
not source.asExpr() instanceof OpenSslDirectAlgorithmOperationCall and
|
||||
not source.asIndirectExpr() instanceof OpenSslDirectAlgorithmOperationCall
|
||||
not source.asExpr() instanceof OpenSslDirectAlgorithmOperationCall
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
@@ -50,12 +46,10 @@ module KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::
|
||||
}
|
||||
|
||||
module KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow =
|
||||
TaintTracking::Global<KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig>;
|
||||
DataFlow::Global<KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig>;
|
||||
|
||||
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof OpenSslSpecialPaddingLiteral
|
||||
}
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof OpenSslPaddingLiteral }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(PaddingAlgorithmValueConsumer c | c.getInputNode() = sink)
|
||||
@@ -67,7 +61,7 @@ module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataF
|
||||
}
|
||||
|
||||
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
|
||||
TaintTracking::Global<RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
|
||||
DataFlow::Global<RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
|
||||
|
||||
class OpenSslAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep {
|
||||
OpenSslAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) }
|
||||
|
||||
@@ -53,8 +53,7 @@ class KnownOpenSslBlockModeConstantAlgorithmInstance extends OpenSslAlgorithmIns
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
|
||||
@@ -2,10 +2,12 @@ import cpp
|
||||
private import experimental.quantum.Language
|
||||
private import KnownAlgorithmConstants
|
||||
private import Crypto::KeyOpAlg as KeyOpAlg
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import OpenSSLAlgorithmInstances
|
||||
private import OpenSSLAlgorithmInstanceBase
|
||||
private import PaddingAlgorithmInstance
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import AlgToAVCFlow
|
||||
private import BlockAlgorithmInstance
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSslCipherAlgorithmExpr`, converts this to a cipher family type.
|
||||
@@ -77,8 +79,7 @@ class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstan
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
@@ -96,13 +97,10 @@ class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstan
|
||||
}
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() {
|
||||
//TODO: the padding is either self, or it flows through getter ctx to a set padding call
|
||||
// like EVP_PKEY_CTX_set_rsa_padding
|
||||
result = this
|
||||
or
|
||||
exists(OperationStep s |
|
||||
this.getAvc().(AvcContextCreationStep).flowsToOperationStep(s) and
|
||||
s.getAlgorithmValueConsumerForInput(PaddingAlgorithmIO()) =
|
||||
result.(OpenSslAlgorithmInstance).getAvc()
|
||||
)
|
||||
// TODO or trace through getter ctx to set padding
|
||||
}
|
||||
|
||||
override string getRawAlgorithmName() {
|
||||
@@ -119,7 +117,7 @@ class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstan
|
||||
knownOpenSslConstantToCipherFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSslConstantToCipherFamilyType(this, _) and
|
||||
result = Crypto::KeyOpAlg::TOtherKeyOperationAlgorithmType()
|
||||
result = Crypto::KeyOpAlg::TUnknownKeyOperationAlgorithmType()
|
||||
}
|
||||
|
||||
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
|
||||
|
||||
@@ -21,8 +21,7 @@ class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorith
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
@@ -40,7 +39,7 @@ class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorith
|
||||
result = this.(Call).getTarget().getName()
|
||||
}
|
||||
|
||||
override Crypto::EllipticCurveType getEllipticCurveType() {
|
||||
override Crypto::EllipticCurveFamilyType getEllipticCurveFamilyType() {
|
||||
if
|
||||
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
|
||||
_)
|
||||
|
||||
@@ -59,8 +59,7 @@ class KnownOpenSslHashConstantAlgorithmInstance extends OpenSslAlgorithmInstance
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
@@ -72,7 +71,7 @@ class KnownOpenSslHashConstantAlgorithmInstance extends OpenSslAlgorithmInstance
|
||||
|
||||
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
|
||||
|
||||
override Crypto::THashType getHashType() {
|
||||
override Crypto::THashType getHashFamily() {
|
||||
knownOpenSslConstantToHashFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSslConstantToHashFamilyType(this, _) and result = Crypto::OtherHashType()
|
||||
|
||||
@@ -37,8 +37,7 @@ class KnownOpenSslKeyAgreementConstantAlgorithmInstance extends OpenSslAlgorithm
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
|
||||
@@ -171,15 +171,9 @@ class KnownOpenSslKeyAgreementAlgorithmExpr extends Expr instanceof KnownOpenSsl
|
||||
}
|
||||
|
||||
predicate knownOpenSslAlgorithmOperationCall(Call c, string normalized, string algType) {
|
||||
c.getTarget().getName() in [
|
||||
"EVP_RSA_gen", "RSA_generate_key_ex", "RSA_generate_key", "RSA_new", "RSA_sign", "RSA_verify"
|
||||
] and
|
||||
c.getTarget().getName() in ["EVP_RSA_gen", "RSA_generate_key_ex", "RSA_generate_key", "RSA_new"] and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
or
|
||||
c.getTarget().getName() in ["DSA_do_sign", "DSA_do_verify"] and
|
||||
normalized = "DSA" and
|
||||
algType = "SIGNATURE"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,13 +2,12 @@ import cpp
|
||||
private import experimental.quantum.Language
|
||||
private import KnownAlgorithmConstants
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
||||
private import Crypto::KeyOpAlg as KeyOpAlg
|
||||
private import AlgToAVCFlow
|
||||
|
||||
class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::KeyOperationAlgorithmInstance instanceof KnownOpenSslMacAlgorithmExpr
|
||||
Crypto::MacAlgorithmInstance instanceof KnownOpenSslMacAlgorithmExpr
|
||||
{
|
||||
OpenSslAlgorithmValueConsumer getterCall;
|
||||
|
||||
@@ -22,8 +21,7 @@ class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
@@ -35,34 +33,17 @@ class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
|
||||
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
|
||||
|
||||
override string getRawAlgorithmName() {
|
||||
override string getRawMacAlgorithmName() {
|
||||
result = this.(Literal).getValue().toString()
|
||||
or
|
||||
result = this.(Call).getTarget().getName()
|
||||
}
|
||||
|
||||
override Crypto::KeyOpAlg::AlgorithmType getAlgorithmType() {
|
||||
if this instanceof KnownOpenSslHMacAlgorithmExpr
|
||||
then result = KeyOpAlg::TMac(KeyOpAlg::HMAC())
|
||||
else
|
||||
if this instanceof KnownOpenSslCMacAlgorithmExpr
|
||||
then result = KeyOpAlg::TMac(KeyOpAlg::CMAC())
|
||||
else result = KeyOpAlg::TMac(KeyOpAlg::OtherMacAlgorithmType())
|
||||
override Crypto::MacType getMacType() {
|
||||
this instanceof KnownOpenSslHMacAlgorithmExpr and result = Crypto::HMAC()
|
||||
or
|
||||
this instanceof KnownOpenSslCMacAlgorithmExpr and result = Crypto::CMAC()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
|
||||
// TODO: trace to any key size initializer?
|
||||
none()
|
||||
}
|
||||
|
||||
override int getKeySizeFixed() {
|
||||
// TODO: are there known fixed key sizes to consider?
|
||||
none()
|
||||
}
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { none() }
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
|
||||
}
|
||||
|
||||
class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HmacAlgorithmInstance,
|
||||
@@ -79,13 +60,9 @@ class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HmacAlgorithmIns
|
||||
// where the current AVC traces to a HashAlgorithmIO consuming operation step.
|
||||
// TODO: need to consider getting reset values, tracing down to the first set for now
|
||||
exists(OperationStep s, AvcContextCreationStep avc |
|
||||
avc = super.getAvc() and
|
||||
avc = this.getAvc() and
|
||||
avc.flowsToOperationStep(s) and
|
||||
s.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
||||
)
|
||||
}
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { none() }
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import cpp
|
||||
private import experimental.quantum.Language
|
||||
private import OpenSSLAlgorithmInstanceBase
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
private import AlgToAVCFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as KeyOpAlg
|
||||
|
||||
/**
|
||||
@@ -18,14 +18,13 @@ private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as K
|
||||
* # define RSA_PKCS1_WITH_TLS_PADDING 7
|
||||
* # define RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING 8
|
||||
*/
|
||||
class OpenSslSpecialPaddingLiteral extends Literal {
|
||||
class OpenSslPaddingLiteral extends Literal {
|
||||
// TODO: we can be more specific about where the literal is in a larger expression
|
||||
// to avoid literals that are clealy not representing an algorithm, e.g., array indices.
|
||||
OpenSslSpecialPaddingLiteral() { this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8] }
|
||||
OpenSslPaddingLiteral() { this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8] }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` has the given `type`.
|
||||
* Given a `KnownOpenSslPaddingAlgorithmExpr`, converts this to a padding family type.
|
||||
* Does not bind if there is no mapping (no mapping to 'unknown' or 'other').
|
||||
*/
|
||||
@@ -46,6 +45,9 @@ predicate knownOpenSslConstantToPaddingFamilyType(
|
||||
)
|
||||
}
|
||||
|
||||
//abstract class OpenSslPaddingAlgorithmInstance extends OpenSslAlgorithmInstance, Crypto::PaddingAlgorithmInstance{}
|
||||
// TODO: need to alter this to include known padding constants which don't have the
|
||||
// same mechanics as those with known nids
|
||||
class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::PaddingAlgorithmInstance instanceof Expr
|
||||
{
|
||||
@@ -64,8 +66,7 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) and
|
||||
isPaddingSpecificConsumer = false
|
||||
@@ -78,13 +79,12 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
isPaddingSpecificConsumer = false
|
||||
or
|
||||
// Possibility 3: padding-specific literal
|
||||
this instanceof OpenSslSpecialPaddingLiteral and
|
||||
this instanceof OpenSslPaddingLiteral and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a padding-specific consumer
|
||||
RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
) and
|
||||
@@ -124,6 +124,44 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
}
|
||||
}
|
||||
|
||||
// // Values used for EVP_PKEY_CTX_set_rsa_padding, these are
|
||||
// // not the same as 'typical' constants found in the set of known algorithm constants
|
||||
// // they do not have an NID
|
||||
// // TODO: what about setting the padding directly?
|
||||
// class KnownRSAPaddingConstant extends OpenSslPaddingAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof Literal
|
||||
// {
|
||||
// KnownRSAPaddingConstant() {
|
||||
// // from rsa.h in openssl:
|
||||
// // # define RSA_PKCS1_PADDING 1
|
||||
// // # define RSA_NO_PADDING 3
|
||||
// // # define RSA_PKCS1_OAEP_PADDING 4
|
||||
// // # define RSA_X931_PADDING 5
|
||||
// // /* EVP_PKEY_ only */
|
||||
// // # define RSA_PKCS1_PSS_PADDING 6
|
||||
// // # define RSA_PKCS1_WITH_TLS_PADDING 7
|
||||
// // /* internal RSA_ only */
|
||||
// // # define RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING 8
|
||||
// this instanceof Literal and
|
||||
// this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8]
|
||||
// // TODO: trace to padding-specific consumers
|
||||
// RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
|
||||
// }
|
||||
// override string getRawPaddingAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
// override Crypto::TPaddingType getPaddingType() {
|
||||
// if this.(Literal).getValue().toInt() in [1, 6, 7, 8]
|
||||
// then result = Crypto::PKCS1_v1_5()
|
||||
// else
|
||||
// if this.(Literal).getValue().toInt() = 3
|
||||
// then result = Crypto::NoPadding()
|
||||
// else
|
||||
// if this.(Literal).getValue().toInt() = 4
|
||||
// then result = Crypto::OAEP()
|
||||
// else
|
||||
// if this.(Literal).getValue().toInt() = 5
|
||||
// then result = Crypto::ANSI_X9_23()
|
||||
// else result = Crypto::OtherPadding()
|
||||
// }
|
||||
// }
|
||||
class OaepPaddingAlgorithmInstance extends Crypto::OaepPaddingAlgorithmInstance,
|
||||
KnownOpenSslPaddingConstantAlgorithmInstance
|
||||
{
|
||||
@@ -132,18 +170,10 @@ class OaepPaddingAlgorithmInstance extends Crypto::OaepPaddingAlgorithmInstance,
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getOaepEncodingHashAlgorithm() {
|
||||
exists(OperationStep s |
|
||||
this.getAvc().(AvcContextCreationStep).flowsToOperationStep(s) and
|
||||
s.getAlgorithmValueConsumerForInput(HashAlgorithmOaepIO()) =
|
||||
result.(OpenSslAlgorithmInstance).getAvc()
|
||||
)
|
||||
none() //TODO
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getMgf1HashAlgorithm() {
|
||||
exists(OperationStep s |
|
||||
this.getAvc().(AvcContextCreationStep).flowsToOperationStep(s) and
|
||||
s.getAlgorithmValueConsumerForInput(HashAlgorithmMgf1IO()) =
|
||||
result.(OpenSslAlgorithmInstance).getAvc()
|
||||
)
|
||||
none() //TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,7 @@ class KnownOpenSslSignatureConstantAlgorithmInstance extends OpenSslAlgorithmIns
|
||||
// Sink is an argument to a signature getter call
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
|
||||
@@ -12,17 +12,15 @@ class EvpCipherAlgorithmValueConsumer extends CipherAlgorithmValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpCipherAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() in ["EVP_get_cipherbyname", "EVP_get_cipherbyobj"] and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_get_cipherbynid" and
|
||||
// algorithm is an NID (int), use asExpr()
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_get_cipherbyname", "EVP_get_cipherbyobj", "EVP_get_cipherbynid"
|
||||
] and
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() in ["EVP_CIPHER_fetch", "EVP_ASYM_CIPHER_fetch"] and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class DirectAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer instanc
|
||||
*/
|
||||
override DataFlow::Node getResultNode() {
|
||||
this instanceof OpenSslDirectAlgorithmFetchCall and
|
||||
result.asIndirectExpr() = this
|
||||
result.asExpr() = this
|
||||
// NOTE: if instanceof OpenSslDirectAlgorithmOperationCall then there is no algorithm generated
|
||||
// the algorithm is directly used
|
||||
}
|
||||
|
||||
@@ -12,19 +12,14 @@ class EvpEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpEllipticCurveAlgorithmConsumer() {
|
||||
resultNode.asIndirectExpr() = this.(Call) and // in all cases the result is the return
|
||||
resultNode.asExpr() = this.(Call) and // in all cases the result is the return
|
||||
(
|
||||
this.(Call).getTarget().getName() = "EVP_EC_gen" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EC_KEY_new_by_curve_name" and
|
||||
// algorithm is an NID (int), use asExpr()
|
||||
this.(Call).getTarget().getName() in ["EVP_EC_gen", "EC_KEY_new_by_curve_name"] and
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EC_KEY_new_by_curve_name_ex", "EVP_PKEY_CTX_set_ec_paramgen_curve_nid"
|
||||
] and
|
||||
// algorithm is an NID (int), use asExpr
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ abstract class HashAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer
|
||||
/**
|
||||
* An EVP_Q_Digest directly consumes algorithm constant values
|
||||
*/
|
||||
class Evp_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer instanceof Call {
|
||||
Evp_Q_Digest_Algorithm_Consumer() { super.getTarget().getName() = "EVP_Q_digest" }
|
||||
class Evp_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer {
|
||||
Evp_Q_Digest_Algorithm_Consumer() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() {
|
||||
result.asIndirectExpr() = super.getArgument(1)
|
||||
result.asExpr() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
@@ -42,7 +42,7 @@ class EvpPkeySetCtxALgorithmConsumer extends HashAlgorithmValueConsumer {
|
||||
"EVP_PKEY_CTX_set_rsa_mgf1_md_name", "EVP_PKEY_CTX_set_rsa_oaep_md_name",
|
||||
"EVP_PKEY_CTX_set_dsa_paramgen_md_props"
|
||||
] and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
override DataFlow::Node getResultNode() { none() }
|
||||
@@ -64,18 +64,18 @@ class EvpDigestAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpDigestAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_get_digestbyname", "EVP_get_digestbynid", "EVP_get_digestbyobj"
|
||||
] and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(0)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_MD_fetch" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(2)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,21 +87,3 @@ class EvpDigestAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
|
||||
exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
|
||||
}
|
||||
}
|
||||
|
||||
class RsaSignOrVerifyHashAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
|
||||
DataFlow::Node valueArgNode;
|
||||
|
||||
RsaSignOrVerifyHashAlgorithmValueConsumer() {
|
||||
this.(Call).getTarget().getName() in ["RSA_sign", "RSA_verify"] and
|
||||
// arg 0 is an int, use asExpr
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getResultNode() { none() }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ class EvpKemAlgorithmValueConsumer extends KemAlgorithmValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpKemAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() = "EVP_KEM_fetch" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ class EvpKeyExchangeAlgorithmValueConsumer extends KeyExchangeAlgorithmValueCons
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpKeyExchangeAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() = "EVP_KEYEXCH_fetch" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class EvpPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpPKeyAlgorithmConsumer() {
|
||||
resultNode.asIndirectExpr() = this.(Call) and // in all cases the result is the return
|
||||
resultNode.asExpr() = this.(Call) and // in all cases the result is the return
|
||||
(
|
||||
// NOTE: some of these consumers are themselves key gen operations,
|
||||
// in these cases, the operation will be created separately for the same function.
|
||||
@@ -19,7 +19,6 @@ class EvpPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
"EVP_PKEY_CTX_new_id", "EVP_PKEY_new_raw_private_key", "EVP_PKEY_new_raw_public_key",
|
||||
"EVP_PKEY_new_mac_key"
|
||||
] and
|
||||
// Algorithm is an int, use asExpr
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() in [
|
||||
@@ -27,8 +26,7 @@ class EvpPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
"EVP_PKEY_new_raw_public_key_ex", "EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_ctrl_uint64",
|
||||
"EVP_PKEY_CTX_ctrl_str", "EVP_PKEY_CTX_set_group_name"
|
||||
] and
|
||||
// AAlgorithm is a char*, use asIndirectExpr
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
or
|
||||
// argInd 2 is 'type' which can be RSA, or EC
|
||||
// if RSA argInd 3 is the key size, else if EC argInd 3 is the curve name
|
||||
@@ -40,10 +38,10 @@ class EvpPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
// Elliptic curve case
|
||||
// If the argInd 3 is a derived type (pointer or array) then assume it is a curve name
|
||||
if this.(Call).getArgument(3).getType().getUnderlyingType() instanceof DerivedType
|
||||
then valueArgNode.asIndirectExpr() = this.(Call).getArgument(3)
|
||||
then valueArgNode.asExpr() = this.(Call).getArgument(3)
|
||||
else
|
||||
// All other cases
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(2)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,9 +14,8 @@ class Evp_PKey_Ctx_set_rsa_padding_AlgorithmValueConsumer extends PaddingAlgorit
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
Evp_PKey_Ctx_set_rsa_padding_AlgorithmValueConsumer() {
|
||||
resultNode.asDefiningArgument() = this.(Call).getArgument(0) and
|
||||
resultNode.asExpr() = this and
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_rsa_padding" and
|
||||
// algorithm is an int, use asExpr
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@ class EvpSignatureAlgorithmValueConsumer extends SignatureAlgorithmValueConsumer
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpSignatureAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
// EVP_SIGNATURE
|
||||
this.(Call).getTarget().getName() = "EVP_SIGNATURE_fetch" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
// EVP_PKEY_get1_DSA, EVP_PKEY_get1_RSA
|
||||
// DSA_SIG_new, DSA_SIG_get0 ?
|
||||
// DSA_SIG_new, DSA_SIG_get0, RSA_sign ?
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
private import experimental.quantum.Language
|
||||
|
||||
/**
|
||||
* A call to `BN_bn2bin`.
|
||||
* Commonly used to extract partial bytes from a signature,
|
||||
* e.g., a signature from DSA_do_sign, passed to DSA_do_verify
|
||||
* - int BN_bn2bin(const BIGNUM *a, unsigned char *to);
|
||||
*/
|
||||
class BnBn2BinCalStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
BnBn2BinCalStep() {
|
||||
call.getTarget().getName() = "BN_bn2bin" and
|
||||
call.getArgument(0) = this.asIndirectExpr()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() { result.asDefiningArgument() = call.getArgument(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `BN_bin2bn`.
|
||||
* Commonly used to convert to a signature for DSA_do_verify
|
||||
* - BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
|
||||
*/
|
||||
class BnBin2BnCallStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
BnBin2BnCallStep() {
|
||||
call.getTarget().getName() = "BN_bin2bn" and
|
||||
call.getArgument(0) = this.asIndirectExpr()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() { result.asDefiningArgument() = call.getArgument(2) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `RSA_set0_key` or `DSA_SIG_set0`.
|
||||
* Often used in combination with BN_bin2bn, to construct a signature.
|
||||
*/
|
||||
class RsaSet0KeyCallStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
RsaSet0KeyCallStep() {
|
||||
(call.getTarget().getName() = "RSA_set0_key" or call.getTarget().getName() = "DSA_SIG_set0") and
|
||||
this.asIndirectExpr() in [call.getArgument(1), call.getArgument(2), call.getArgument(3)]
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() { result.asDefiningArgument() = call.getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `d2i_DSA_SIG`. This is a pass through of a signature of one form to another.
|
||||
* - DSA_SIG *d2i_DSA_SIG(DSA_SIG **sig, const unsigned char **pp, long length);
|
||||
*/
|
||||
class D2iDsaSigCallStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
D2iDsaSigCallStep() {
|
||||
call.getTarget().getName() = "d2i_DSA_SIG" and
|
||||
this.asIndirectExpr() = call.getArgument(1)
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() {
|
||||
// If arg 0 specified, the same pointer is returned, if not specified
|
||||
// a new allocation is returned.
|
||||
result.asDefiningArgument() = call.getArgument(0) or
|
||||
result.asIndirectExpr() = call
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `DSA_SIG_get0`.
|
||||
* Converts a DSA_Sig into its components, which are commonly used with BN_bn2Bin to
|
||||
* construct a char* signature.
|
||||
* - void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
|
||||
*/
|
||||
class DsaSigGet0CallStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
DsaSigGet0CallStep() {
|
||||
call.getTarget().getName() = "DSA_SIG_get0" and
|
||||
this.asIndirectExpr() = call.getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() {
|
||||
result.asDefiningArgument() = call.getArgument(1)
|
||||
or
|
||||
result.asDefiningArgument() = call.getArgument(2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_get1_RSA` or `EVP_PKEY_get1_DSA`
|
||||
* - RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
|
||||
* - DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey);
|
||||
* A key input is converted into a key output, a key is not generated.
|
||||
*/
|
||||
class EvpPkeyGet1RsaOrDsa extends AdditionalFlowInputStep {
|
||||
Call c;
|
||||
|
||||
EvpPkeyGet1RsaOrDsa() {
|
||||
c.getTarget().getName() = ["EVP_PKEY_get1_RSA", "EVP_PKEY_get1_DSA"] and
|
||||
this.asIndirectExpr() = c.getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() { result.asIndirectExpr() = c }
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
/**
|
||||
@@ -13,9 +13,7 @@ module AvcToCallArgConfig implements DataFlow::ConfigSig {
|
||||
* Trace to any call accepting the algorithm.
|
||||
* NOTE: users must restrict this set to the operations they are interested in.
|
||||
*/
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(Call c | c.getAnArgument() = [sink.asIndirectExpr(), sink.asExpr()])
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { exists(Call c | c.getAnArgument() = sink.asExpr()) }
|
||||
}
|
||||
|
||||
module AvcToCallArgFlow = TaintTracking::Global<AvcToCallArgConfig>;
|
||||
module AvcToCallArgFlow = DataFlow::Global<AvcToCallArgConfig>;
|
||||
|
||||
@@ -4,5 +4,4 @@ module OpenSslModel {
|
||||
import Operations.OpenSSLOperations
|
||||
import Random
|
||||
import GenericSourceCandidateLiteral
|
||||
import ArtifactPassthrough
|
||||
}
|
||||
|
||||
@@ -3,48 +3,24 @@ private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import EVPPKeyCtxInitializer
|
||||
|
||||
/**
|
||||
* A base class for all final cipher operation steps.
|
||||
*/
|
||||
abstract class FinalCipherOperationStep extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base configuration for all EVP cipher operations.
|
||||
*/
|
||||
abstract class EvpCipherOperationFinalStep extends FinalCipherOperationStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for all EVP cipher operations.
|
||||
*/
|
||||
abstract class EvpCipherInitializer extends OperationStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
result.asExpr() = this.getArgument(1) and
|
||||
type = PrimaryAlgorithmIO() and
|
||||
// Constants that are not equal to zero or
|
||||
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
|
||||
// A zero (null) value typically indicates use of this operation step to initialize
|
||||
// other out parameters in a multi-step initialization.
|
||||
(
|
||||
exists(result.asIndirectExpr().getValue())
|
||||
implies
|
||||
result.asIndirectExpr().getValue().toInt() != 0
|
||||
)
|
||||
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -62,15 +38,11 @@ abstract class EvpEXInitializer extends EvpCipherInitializer {
|
||||
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
|
||||
// A zero (null) value typically indicates use of this operation step to initialize
|
||||
// other out parameters in a multi-step initialization.
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(3) and type = KeyIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(4) and type = IVorNonceIO()
|
||||
result.asExpr() = this.getArgument(4) and type = IVorNonceIO()
|
||||
) and
|
||||
(
|
||||
exists(result.asIndirectExpr().getValue())
|
||||
implies
|
||||
result.asIndirectExpr().getValue().toInt() != 0
|
||||
)
|
||||
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,9 +53,9 @@ abstract class EvpEX2Initializer extends EvpCipherInitializer {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(2) and type = KeyIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = IVorNonceIO()
|
||||
result.asExpr() = this.getArgument(3) and type = IVorNonceIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +90,6 @@ class Evp_Cipher_EX2_or_Simple_Init_Call extends EvpEX2Initializer {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
this.getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
// the key op subtype is an int, use asExpr
|
||||
result.asExpr() = this.getArgument(4) and
|
||||
type = KeyOperationSubtypeIO()
|
||||
}
|
||||
@@ -136,13 +107,13 @@ class EvpPkeyEncryptDecryptInit extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = OsslParamIO()
|
||||
result.asExpr() = this.getArgument(1) and type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -154,7 +125,6 @@ class EvpCipherInitSKeyCall extends EvpEX2Initializer {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
// the key op subtype is an int, use asExpr
|
||||
result.asExpr() = this.getArgument(5) and
|
||||
type = KeyOperationSubtypeIO()
|
||||
}
|
||||
@@ -171,20 +141,35 @@ class EvpCipherUpdateCall extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = CiphertextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base configuration for all EVP cipher operations.
|
||||
*/
|
||||
abstract class EvpCipherOperationFinalStep extends OperationStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to EVP_Cipher.
|
||||
*/
|
||||
@@ -194,13 +179,13 @@ class EvpCipherCall extends EvpCipherOperationFinalStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
super.getInput(type) = result
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(2) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
super.getOutput(type) = result
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = CiphertextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,50 +216,28 @@ class EvpCipherFinalCall extends EvpCipherOperationFinalStep {
|
||||
*/
|
||||
class EvpPKeyCipherOperation extends EvpCipherOperationFinalStep {
|
||||
EvpPKeyCipherOperation() {
|
||||
this.getTarget().getName() in ["EVP_PKEY_encrypt", "EVP_PKEY_decrypt"] and
|
||||
// TODO: for now ignore this operation entirely if it is setting the cipher text to null
|
||||
// this needs to be re-evalauted if this scenario sets other values worth tracking
|
||||
(
|
||||
exists(this.(Call).getArgument(1).getValue())
|
||||
implies
|
||||
this.(Call).getArgument(1).getValue().toInt() != 0
|
||||
)
|
||||
this.getTarget().getName() in ["EVP_PKEY_encrypt", "EVP_PKEY_decrypt"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
super.getInput(type) = result
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
super.getOutput(type) = result
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and
|
||||
type = CiphertextIO() and
|
||||
this.getStepType() = FinalStep()
|
||||
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
|
||||
// TODO: could indicate text lengths here, as well
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() {
|
||||
// When the output buffer is null, the step is not a final step
|
||||
// it is used to get the buffer size, if 0 consider it an initialization step
|
||||
// NOTE/TODO: not tracing 0 to the arg, just looking for 0 directly in param
|
||||
// the assumption is this is the common case, but we may want to make this more
|
||||
// robust and support a dataflow.
|
||||
result = FinalStep() and
|
||||
(exists(super.getArgument(1).getValue()) implies super.getArgument(1).getValue().toInt() != 0)
|
||||
or
|
||||
result = InitializerStep() and
|
||||
super.getArgument(1).getValue().toInt() = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An EVP cipher operation instance.
|
||||
* Any operation step that is a final operation step for EVP cipher operation steps.
|
||||
*/
|
||||
class OpenSslCipherOperationInstance extends Crypto::KeyOperationInstance instanceof FinalCipherOperationStep
|
||||
class EvpCipherOperationInstance extends Crypto::KeyOperationInstance instanceof EvpCipherOperationFinalStep
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
/**
|
||||
* Initializers for EVP PKey
|
||||
* These are used to create a Pkey context or set properties on a Pkey context
|
||||
* e.g., key size, hash algorithms, curves, padding schemes, etc.
|
||||
* Meant to capture more general purpose initializers that aren't necessarily
|
||||
* tied to a specific operation. If tied to an operation (i.e., in the docs)
|
||||
* we recommend defining defining all together in the same operation definition qll.
|
||||
* including:
|
||||
* https://docs.openssl.org/3.0/man3/EVP_PKEY_CTX_ctrl/
|
||||
* https://docs.openssl.org/3.0/man3/EVP_EncryptInit/#synopsis
|
||||
@@ -31,16 +26,14 @@ class EvpNewKeyCtx extends OperationStep instanceof Call {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = keyArg and type = KeyIO()
|
||||
result.asExpr() = keyArg and type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
|
||||
result.asIndirectExpr() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = OsslLibContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asIndirectExpr() = this and type = ContextIO()
|
||||
}
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = ContextIO() }
|
||||
|
||||
override OperationStepType getStepType() { result = ContextCreationStep() }
|
||||
}
|
||||
@@ -54,13 +47,13 @@ class EvpCtxSetEcParamgenCurveNidInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -78,46 +71,23 @@ class EvpCtxSetEcParamgenCurveNidInitializer extends OperationStep {
|
||||
* - `EVP_PKEY_CTX_set_ecdh_kdf_md`
|
||||
*/
|
||||
class EvpCtxSetHashInitializer extends OperationStep {
|
||||
boolean isOaep;
|
||||
boolean isMgf1;
|
||||
|
||||
EvpCtxSetHashInitializer() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_signature_md", "EVP_PKEY_CTX_set_dsa_paramgen_md",
|
||||
"EVP_PKEY_CTX_set_signature_md", "EVP_PKEY_CTX_set_rsa_mgf1_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_mgf1_md", "EVP_PKEY_CTX_set_rsa_oaep_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_oaep_md", "EVP_PKEY_CTX_set_dsa_paramgen_md",
|
||||
"EVP_PKEY_CTX_set_dh_kdf_md", "EVP_PKEY_CTX_set_ecdh_kdf_md"
|
||||
] and
|
||||
isOaep = false and
|
||||
isMgf1 = false
|
||||
or
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_rsa_mgf1_md_name", "EVP_PKEY_CTX_set_rsa_mgf1_md"
|
||||
] and
|
||||
isOaep = false and
|
||||
isMgf1 = true
|
||||
or
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_rsa_oaep_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_oaep_md"
|
||||
] and
|
||||
isOaep = true and
|
||||
isMgf1 = false
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
type = HashAlgorithmIO() and
|
||||
isOaep = false and
|
||||
isMgf1 = false
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmOaepIO() and isOaep = true
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmMgf1IO() and isMgf1 = true
|
||||
result.asExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -136,13 +106,13 @@ class EvpCtxSetKeySizeInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = KeySizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -152,16 +122,16 @@ class EvpCtxSetMacKeyInitializer extends OperationStep {
|
||||
EvpCtxSetMacKeyInitializer() { this.getTarget().getName() = "EVP_PKEY_CTX_set_mac_key" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = KeySizeIO()
|
||||
or
|
||||
// the raw key that is configured into the output key
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(1) and type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -173,14 +143,13 @@ class EvpCtxSetPaddingInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// The algorithm is an int: use asExpr
|
||||
result.asExpr() = this.getArgument(1) and type = PaddingAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -192,13 +161,13 @@ class EvpCtxSetSaltLengthInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = SaltLengthIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
|
||||
@@ -6,13 +6,6 @@ private import experimental.quantum.Language
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
/**
|
||||
* A base class for final digest operations.
|
||||
*/
|
||||
abstract class FinalDigestOperation extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to and EVP digest initializer, such as:
|
||||
* - `EVP_DigestInit`
|
||||
@@ -25,13 +18,13 @@ class EvpDigestInitVariantCalls extends OperationStep instanceof Call {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
}
|
||||
|
||||
@@ -45,49 +38,56 @@ class EvpDigestUpdateCall extends OperationStep instanceof Call {
|
||||
EvpDigestUpdateCall() { this.getTarget().getName() = "EVP_DigestUpdate" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for final digest operations.
|
||||
*/
|
||||
abstract class EvpFinalDigestOperationStep extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_Q_digest`
|
||||
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
*/
|
||||
class EvpQDigestOperation extends FinalDigestOperation instanceof Call {
|
||||
class EvpQDigestOperation extends EvpFinalDigestOperationStep instanceof Call {
|
||||
EvpQDigestOperation() { this.getTarget().getName() = "EVP_Q_digest" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(5) and type = DigestIO()
|
||||
}
|
||||
}
|
||||
|
||||
class EvpDigestOperation extends FinalDigestOperation instanceof Call {
|
||||
class EvpDigestOperation extends EvpFinalDigestOperationStep instanceof Call {
|
||||
EvpDigestOperation() { this.getTarget().getName() = "EVP_Digest" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(4) and type = PrimaryAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(4) and type = PrimaryAlgorithmIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
@@ -98,28 +98,27 @@ class EvpDigestOperation extends FinalDigestOperation instanceof Call {
|
||||
/**
|
||||
* A call to EVP_DigestFinal variants
|
||||
*/
|
||||
class EvpDigestFinalCall extends FinalDigestOperation instanceof Call {
|
||||
class EvpDigestFinalCall extends EvpFinalDigestOperationStep instanceof Call {
|
||||
EvpDigestFinalCall() {
|
||||
this.getTarget().getName() in ["EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = DigestIO()
|
||||
//result.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = this.getArgument(1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An openssl digest final hash operation instance
|
||||
*/
|
||||
class OpenSslDigestFinalOperationInstance extends Crypto::HashOperationInstance instanceof FinalDigestOperation
|
||||
class EvpDigestFinalOperationInstance extends Crypto::HashOperationInstance instanceof EvpFinalDigestOperationStep
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
|
||||
@@ -13,12 +13,10 @@ class ECKeyGen extends OperationStep instanceof Call {
|
||||
ECKeyGen() { this.(Call).getTarget().getName() = "EC_KEY_generate_key" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.(Call).getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.(Call).getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this and type = KeyIO()
|
||||
}
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
|
||||
|
||||
override OperationStepType getStepType() { result = ContextCreationStep() }
|
||||
}
|
||||
@@ -35,19 +33,16 @@ class EvpKeyGenInitialize extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for final key generation operation steps.
|
||||
*/
|
||||
abstract class KeyGenFinalOperationStep extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
@@ -59,26 +54,26 @@ class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
EvpPKeyQKeyGen() { this.getTarget().getName() = "EVP_PKEY_Q_keygen" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this and type = KeyIO()
|
||||
result.asExpr() = this and type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// When arg 3 is a derived type, it is a curve name, otherwise it is a key size for RSA if provided
|
||||
// and arg 2 is the algorithm type
|
||||
this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
result.asExpr() = this.getArgument(3) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
|
||||
result.asIndirectExpr() = this.getArgument(2) and
|
||||
result.asExpr() = this.getArgument(2) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
result.asExpr() = this.getArgument(3) and
|
||||
type = KeySizeIO()
|
||||
}
|
||||
}
|
||||
@@ -89,9 +84,7 @@ class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
class EvpRsaGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
EvpRsaGen() { this.getTarget().getName() = "EVP_RSA_gen" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this and type = KeyIO()
|
||||
}
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
|
||||
@@ -104,9 +97,7 @@ class EvpRsaGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
class RsaGenerateKey extends KeyGenFinalOperationStep instanceof Call {
|
||||
RsaGenerateKey() { this.getTarget().getName() = "RSA_generate_key" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this and type = KeyIO()
|
||||
}
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
|
||||
@@ -126,7 +117,7 @@ class RsaGenerateKeyEx extends KeyGenFinalOperationStep instanceof Call {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
// arg 0 comes in as a blank RSA key, which we consider a context,
|
||||
// on output it is considered a key
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,13 +128,13 @@ class EvpPkeyGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
EvpPkeyGen() { this.getTarget().getName() in ["EVP_PKEY_generate", "EVP_PKEY_keygen"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = KeyIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,14 +146,18 @@ class EvpNewMacKey extends KeyGenFinalOperationStep {
|
||||
EvpNewMacKey() { this.getTarget().getName() = "EVP_PKEY_new_mac_key" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// the raw key that is configured into the output key
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(2) and type = KeyIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(3) and type = KeySizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asIndirectExpr() = this and type = KeyIO()
|
||||
result.asExpr() = this and type = KeyIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +165,7 @@ class EvpNewMacKey extends KeyGenFinalOperationStep {
|
||||
/**
|
||||
* An `KeyGenerationOperationInstance` for the for all key gen final operation steps.
|
||||
*/
|
||||
class OpenSslKeyGenOperationInstance extends Crypto::KeyGenerationOperationInstance instanceof KeyGenFinalOperationStep
|
||||
class KeyGenOperationInstance extends Crypto::KeyGenerationOperationInstance instanceof KeyGenFinalOperationStep
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
// Importing these intializers here to ensure the are part of any model that is
|
||||
// using OpenSslOperationBase. This further ensures that initializers are tied to opeartions
|
||||
// even if only importing the operation by itself.
|
||||
@@ -58,11 +58,7 @@ newtype TIOType =
|
||||
// For OSSL_PARAM and OSSL_LIB_CTX use of OsslParamIO and OsslLibContextIO
|
||||
ContextIO() or
|
||||
DigestIO() or
|
||||
// For OAEP and MGF1 hashes, there is a special IO type for these hashes
|
||||
// it is recommended to set the most explicit type known, not both
|
||||
HashAlgorithmIO() or
|
||||
HashAlgorithmOaepIO() or
|
||||
HashAlgorithmMgf1IO() or
|
||||
IVorNonceIO() or
|
||||
KeyIO() or
|
||||
KeyOperationSubtypeIO() or
|
||||
@@ -75,13 +71,11 @@ newtype TIOType =
|
||||
PaddingAlgorithmIO() or
|
||||
// Plaintext also includes a message for digest, signature, verification, and mac generation
|
||||
PlaintextIO() or
|
||||
PlaintextSizeIO() or
|
||||
PrimaryAlgorithmIO() or
|
||||
RandomSourceIO() or
|
||||
SaltLengthIO() or
|
||||
SeedIO() or
|
||||
SignatureIO() or
|
||||
SignatureSizeIO()
|
||||
SignatureIO()
|
||||
|
||||
private string ioTypeToString(TIOType t) {
|
||||
t = CiphertextIO() and result = "CiphertextIO"
|
||||
@@ -110,8 +104,6 @@ private string ioTypeToString(TIOType t) {
|
||||
or
|
||||
t = PlaintextIO() and result = "PlaintextIO"
|
||||
or
|
||||
t = PlaintextSizeIO() and result = "PlaintextSizeIO"
|
||||
or
|
||||
t = PrimaryAlgorithmIO() and result = "PrimaryAlgorithmIO"
|
||||
or
|
||||
t = RandomSourceIO() and result = "RandomSourceIO"
|
||||
@@ -121,8 +113,6 @@ private string ioTypeToString(TIOType t) {
|
||||
t = SeedIO() and result = "SeedIO"
|
||||
or
|
||||
t = SignatureIO() and result = "SignatureIO"
|
||||
or
|
||||
t = SignatureSizeIO() and result = "SignatureSizeIO"
|
||||
}
|
||||
|
||||
class IOType extends TIOType {
|
||||
@@ -133,13 +123,13 @@ class IOType extends TIOType {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: add more initializers as needed
|
||||
/**
|
||||
* The type of step in an `OperationStep`.
|
||||
* - `ContextCreationStep`: the creation of a context from an algorithm or key.
|
||||
* for example `EVP_MD_CTX_create(EVP_sha256())` or `EVP_PKEY_CTX_new(pkey, NULL)`
|
||||
* - `InitializerStep`: the initialization of an operation or state through some sort of shared/accumulated context
|
||||
* for example `EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)`, may also be used for pass through
|
||||
* configuration, for example `EVP_PKEY_get1_RSA(key)` where a pkey is input into an RSA key return.
|
||||
* - `InitializerStep`: the initialization of an operation through some sort of shared/accumulated context
|
||||
* for example `EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)`
|
||||
* - `UpdateStep`: any operation that has and update/final paradigm, the update represents an intermediate step in an operation,
|
||||
* such as `EVP_DigestUpdate(ctx, data, len)`
|
||||
* - `FinalStep`: an ultimate operation step. This may be an explicit 'final' in an update/final paradigm, but not necessarily.
|
||||
@@ -199,7 +189,7 @@ abstract class OperationStep extends Call {
|
||||
*/
|
||||
predicate flowsToOperationStep(OperationStep sink) {
|
||||
sink = this or
|
||||
OperationStepCtxFlow::flow(this.getAnOutput(), [sink.getAnInput(), sink.getAnOutput()])
|
||||
OperationStepFlow::flow(this.getAnOutput(), sink.getAnInput())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +198,7 @@ abstract class OperationStep extends Call {
|
||||
*/
|
||||
predicate flowsFromOperationStep(OperationStep source) {
|
||||
source = this or
|
||||
OperationStepCtxFlow::flow(source.getAnOutput(), [this.getAnInput(), this.getAnOutput()])
|
||||
OperationStepFlow::flow(source.getAnOutput(), this.getAnInput())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,13 +220,10 @@ abstract class OperationStep extends Call {
|
||||
result.setsValue(type) and
|
||||
(
|
||||
// Do not consider a 'reset' to occur on updates
|
||||
// but only for resets that are part of the same update/finalize
|
||||
// progression (e.g., an update for an unrelated finalize is ignored)
|
||||
result.getStepType() = UpdateStep()
|
||||
or
|
||||
not exists(OperationStep reset |
|
||||
result != reset and
|
||||
result != this and
|
||||
reset.setsValue(type) and
|
||||
reset.flowsToOperationStep(this) and
|
||||
result.flowsToOperationStep(reset)
|
||||
@@ -258,11 +245,8 @@ abstract class OperationStep extends Call {
|
||||
|
||||
/**
|
||||
* Gets an AVC for the primary algorithm for this operation.
|
||||
* A primary algorithm is an AVC that either:
|
||||
* 0) `this` is an AVC (consider direct algorithm consumers like RSA_sign (algorithm is implicit) or EVP_PKEY_new_mac_key (NID is first arg) )
|
||||
* 1) flows to a ctx input directly or
|
||||
* 2) flows to a primary algorithm input directly or
|
||||
* 3) flows to a key input directly (algorithm held in a key will be considered primary)
|
||||
* A primary algorithm is an AVC that flows to a ctx input directly or
|
||||
* an AVC that flows to a primary algorithm input directly.
|
||||
* See `AvcContextCreationStep` for details about resetting scenarios.
|
||||
* Gets the first OperationStep an AVC flows to. If a context input,
|
||||
* the AVC is considered primary.
|
||||
@@ -270,24 +254,19 @@ abstract class OperationStep extends Call {
|
||||
* operation step (dominating operation step, see `getDominatingInitializersToStep`).
|
||||
*/
|
||||
Crypto::AlgorithmValueConsumer getPrimaryAlgorithmValueConsumer() {
|
||||
this instanceof Crypto::AlgorithmValueConsumer and result = this
|
||||
or
|
||||
exists(
|
||||
DataFlow::Node src, DataFlow::Node sink, IOType srcIntype, OperationStep avcConsumingPred
|
||||
|
|
||||
(srcIntype = ContextIO() or srcIntype = PrimaryAlgorithmIO() or srcIntype = KeyIO()) and
|
||||
avcConsumingPred.flowsToOperationStep(this) and
|
||||
src.asIndirectExpr() = result and
|
||||
sink = avcConsumingPred.getInput(srcIntype) and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink, IOType t, OperationStep avcSucc |
|
||||
(t = PrimaryAlgorithmIO() or t = ContextIO()) and
|
||||
avcSucc.flowsToOperationStep(this) and
|
||||
src.asExpr() = result and
|
||||
sink = avcSucc.getInput(t) and
|
||||
AvcToOperationStepFlow::flow(src, sink) and
|
||||
(
|
||||
// Case 1: the avcConsumingPred step is a dominating primary algorithm initialization step
|
||||
// or dominating key initialization step
|
||||
(srcIntype = PrimaryAlgorithmIO() or srcIntype = KeyIO()) and
|
||||
avcConsumingPred = this.getDominatingInitializersToStep(srcIntype)
|
||||
// Case 1: the avcSucc step is a dominating initialization step
|
||||
t = PrimaryAlgorithmIO() and
|
||||
avcSucc = this.getDominatingInitializersToStep(PrimaryAlgorithmIO())
|
||||
or
|
||||
// Case 2: the pred is a context input
|
||||
srcIntype = ContextIO()
|
||||
// Case 2: the succ is a context input (any avcSucc is valid)
|
||||
t = ContextIO()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -298,11 +277,9 @@ abstract class OperationStep extends Call {
|
||||
* TODO: generalize to use this for `getPrimaryAlgorithmValueConsumer`
|
||||
*/
|
||||
Crypto::AlgorithmValueConsumer getAlgorithmValueConsumerForInput(IOType type) {
|
||||
result = this and this.setsValue(type)
|
||||
or
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
AvcToOperationStepFlow::flow(src, sink) and
|
||||
src.asIndirectExpr() = result and
|
||||
src.asExpr() = result and
|
||||
sink = this.getInput(type)
|
||||
)
|
||||
}
|
||||
@@ -380,7 +357,7 @@ private class CtxCopyOutArgCall extends CtxPassThroughCall {
|
||||
|
||||
CtxCopyOutArgCall() {
|
||||
this.getTarget().getName().toLowerCase().matches("%copy%") and
|
||||
n1.asIndirectExpr() = this.getAnArgument() and
|
||||
n1.asExpr() = this.getAnArgument() and
|
||||
n1.getType() instanceof CtxType and
|
||||
n2.asDefiningArgument() = this.getAnArgument() and
|
||||
n2.getType() instanceof CtxType and
|
||||
@@ -401,18 +378,16 @@ private class CtxCopyReturnCall extends CtxPassThroughCall, CtxPointerExpr {
|
||||
|
||||
CtxCopyReturnCall() {
|
||||
this.getTarget().getName().toLowerCase().matches("%dup%") and
|
||||
n1.asIndirectExpr() = this.getAnArgument() and
|
||||
n1.asExpr() = this.getAnArgument() and
|
||||
n1.getType() instanceof CtxType
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result.asIndirectExpr() = this }
|
||||
override DataFlow::Node getNode2() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
// TODO: is this still needed? It appears to be (tests fail without it) but
|
||||
// I don't know why as EVP_PKEY_paramgen is an operation step and we pass through
|
||||
// operation steps already.
|
||||
// TODO: is this still needed?
|
||||
/**
|
||||
* A call to `EVP_PKEY_paramgen` acts as a kind of pass through.
|
||||
* It's output pkey is eventually used in a new operation generating
|
||||
@@ -426,10 +401,34 @@ private class CtxParamGenCall extends CtxPassThroughCall {
|
||||
|
||||
CtxParamGenCall() {
|
||||
this.getTarget().getName() = "EVP_PKEY_paramgen" and
|
||||
//Arg 0 is *ctx
|
||||
n1.asIndirectExpr() = this.getArgument(0) and
|
||||
//Arg 1 is **pkey
|
||||
n2.asDefiningArgument() = this.getArgument(1)
|
||||
n1.asExpr() = this.getArgument(0) and
|
||||
(
|
||||
n2.asExpr() = this.getArgument(1)
|
||||
or
|
||||
n2.asDefiningArgument() = this.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result = n2 }
|
||||
}
|
||||
|
||||
//TODO: I am not sure CallArgToCtxRet is needed anymore
|
||||
/**
|
||||
* If the current node is an argument to a function
|
||||
* that returns a pointer type, immediately flow through.
|
||||
* NOTE: this passthrough is required if we allow
|
||||
* intermediate steps to go into variables that are not a CTX type.
|
||||
* See for example `CtxParamGenCall`.
|
||||
*/
|
||||
private class CallArgToCtxRet extends CtxPassThroughCall, CtxPointerExpr {
|
||||
DataFlow::Node n1;
|
||||
DataFlow::Node n2;
|
||||
|
||||
CallArgToCtxRet() {
|
||||
this.getAnArgument() = n1.asExpr() and
|
||||
n2.asExpr() = this
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
@@ -440,7 +439,7 @@ private class CtxParamGenCall extends CtxPassThroughCall {
|
||||
/**
|
||||
* A flow configuration from any non-final `OperationStep` to any other `OperationStep`.
|
||||
*/
|
||||
module OperationStepCtxFlowConfig implements DataFlow::ConfigSig {
|
||||
module OperationStepFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(OperationStep s |
|
||||
s.getAnOutput() = source or
|
||||
@@ -456,39 +455,22 @@ module OperationStepCtxFlowConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(CtxClearCall c | c.getAnArgument() = [node.asExpr(), node.asIndirectExpr()])
|
||||
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
or
|
||||
exists(CtxPassThroughCall c | c.getNode1() = node1 and c.getNode2() = node2)
|
||||
or
|
||||
// Flow only through context and key inputs and outputs
|
||||
// keys and context generally hold unifying context that link multiple steps
|
||||
// Flow only out of finalize operations through key outputs, otherwise stop at final operations
|
||||
exists(OperationStep s, IOType inType, IOType outType |
|
||||
(s.getStepType() = FinalStep() implies outType = KeyIO()) and
|
||||
(
|
||||
inType = ContextIO()
|
||||
or
|
||||
inType = KeyIO()
|
||||
) and
|
||||
(
|
||||
outType = ContextIO()
|
||||
or
|
||||
outType = KeyIO()
|
||||
) and
|
||||
s.getInput(inType) = node1 and
|
||||
s.getOutput(outType) = node2
|
||||
)
|
||||
// Flow out through all outputs from an operation step if more than one output
|
||||
// is defined.
|
||||
exists(OperationStep s | s.getAnInput() = node1 and s.getAnOutput() = node2)
|
||||
// TODO: consideration for additional alises defined as follows:
|
||||
// if an output from an operation step itself flows from the output of another operation step
|
||||
// then the source of that flow's outputs (all of them) are potential aliases
|
||||
}
|
||||
}
|
||||
|
||||
module OperationStepCtxFlow = TaintTracking::Global<OperationStepCtxFlowConfig>;
|
||||
module OperationStepFlow = DataFlow::Global<OperationStepFlowConfig>;
|
||||
|
||||
/**
|
||||
* A flow from AVC to the first `OperationStep` the AVC reaches as an input.
|
||||
@@ -501,7 +483,7 @@ module AvcToOperationStepFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { exists(OperationStep s | s.getAnInput() = sink) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(CtxClearCall c | c.getAnArgument() = [node.asExpr(), node.asIndirectExpr()])
|
||||
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,7 +496,7 @@ module AvcToOperationStepFlowConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
}
|
||||
|
||||
module AvcToOperationStepFlow = TaintTracking::Global<AvcToOperationStepFlowConfig>;
|
||||
module AvcToOperationStepFlow = DataFlow::Global<AvcToOperationStepFlowConfig>;
|
||||
|
||||
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
|
||||
@@ -524,7 +506,7 @@ module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
}
|
||||
|
||||
module EncValToInitEncArgFlow = TaintTracking::Global<EncValToInitEncArgConfig>;
|
||||
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
|
||||
|
||||
private Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
|
||||
i = 0 and
|
||||
|
||||
@@ -6,25 +6,12 @@ private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AvcFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
|
||||
// TODO: verification functions
|
||||
/**
|
||||
* A base class for final signature operations.
|
||||
* The operation must be known to always be a signature operation,
|
||||
* and not a MAC operation. Used for both verification and signing.
|
||||
* NOTE: even an operation that may be a mac or signature but is known to take in
|
||||
* only signature configurations should extend `SignatureOrMacFinalOperation`.
|
||||
*/
|
||||
abstract class SignatureFinalOperation extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for final signature or MAC operations.
|
||||
* The operation must be known to always be a signature or MAC operation.
|
||||
* Used for both verification or signing.
|
||||
*/
|
||||
abstract class SignatureOrMacFinalOperation extends OperationStep {
|
||||
abstract class EvpSignatureFinalOperation extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
@@ -37,32 +24,36 @@ class EvpSignatureDigestInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
result.asExpr() = this.getArgument(3) and
|
||||
type = OsslLibContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = HashAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(2) and type = HashAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit" and
|
||||
result.asIndirectExpr() = this.getArgument(4) and
|
||||
result.asExpr() = this.getArgument(4) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(5) and
|
||||
result.asExpr() = this.getArgument(5) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(6) and
|
||||
result.asExpr() = this.getArgument(6) and
|
||||
type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// EVP_PKEY_CTX
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asExpr() = this.getArgument(6) and
|
||||
type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -75,13 +66,13 @@ class EvpSignInit extends OperationStep {
|
||||
EvpSignInit() { this.getTarget().getName() in ["EVP_SignInit", "EVP_SignInit_ex"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -103,22 +94,22 @@ class EvpPkeySignInit extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
result.asExpr() = this.getArgument(1) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_PKEY_sign_init_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
result.asExpr() = this.getArgument(1) and
|
||||
type = OsslParamIO()
|
||||
or
|
||||
// Argument 2 (0 based) only exists for EVP_PKEY_sign_init_ex2 and EVP_PKEY_sign_message_init
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = OsslParamIO()
|
||||
result.asExpr() = this.getArgument(2) and type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -135,13 +126,13 @@ class EvpSignatureUpdateCall extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
@@ -150,496 +141,73 @@ class EvpSignatureUpdateCall extends OperationStep {
|
||||
/**
|
||||
* A call to EVP_SignFinal or EVP_SignFinal_ex.
|
||||
*/
|
||||
class EvpSignFinal extends SignatureFinalOperation {
|
||||
class EvpSignFinal extends EvpSignatureFinalOperation {
|
||||
EvpSignFinal() { this.getTarget().getName() in ["EVP_SignFinal_ex", "EVP_SignFinal"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(3) and type = KeyIO()
|
||||
or
|
||||
// params above 3 (0-based) only exist for EVP_SignFinal_ex
|
||||
result.asIndirectExpr() = this.getArgument(4) and
|
||||
result.asExpr() = this.getArgument(4) and
|
||||
type = OsslLibContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
result.asExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_PKEY_sign.
|
||||
* A call to EVP_DigestSign or EVP_PKEY_sign.
|
||||
*/
|
||||
class EvpPkeySign extends SignatureFinalOperation {
|
||||
EvpPkeySign() {
|
||||
this.getTarget().getName() = "EVP_PKEY_sign" and
|
||||
// Setting signature to NULL is not a final sign step but an
|
||||
// intermediary step used to get the required buffer size.
|
||||
// not tracking these calls.
|
||||
(
|
||||
exists(this.(Call).getArgument(1).getValue())
|
||||
implies
|
||||
this.(Call).getArgument(1).getValue().toInt() != 0
|
||||
)
|
||||
}
|
||||
class EvpDigestSign extends EvpSignatureFinalOperation {
|
||||
EvpDigestSign() { this.getTarget().getName() in ["EVP_DigestSign", "EVP_PKEY_sign"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
result.asExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestSign.
|
||||
* This is a mac or sign operation.
|
||||
* A call to EVP_DigestSignFinal or EVP_PKEY_sign_message_final.
|
||||
*/
|
||||
class EvpDigestSign extends SignatureOrMacFinalOperation {
|
||||
EvpDigestSign() { this.getTarget().getName() = "EVP_DigestSign" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_PKEY_sign_message_final.
|
||||
*/
|
||||
class EvpPkeySignFinal extends SignatureFinalOperation {
|
||||
EvpPkeySignFinal() {
|
||||
this.getTarget().getName() = "EVP_PKEY_sign_message_final" and
|
||||
// Setting signature to NULL is not a final sign step but an
|
||||
// intermediary step used to get the required buffer size.
|
||||
// not tracking these calls.
|
||||
(
|
||||
exists(this.(Call).getArgument(1).getValue())
|
||||
implies
|
||||
this.(Call).getArgument(1).getValue().toInt() != 0
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestSignFinal.
|
||||
* This is a mac or sign operation.
|
||||
*/
|
||||
class EvpDigestSignFinal extends SignatureOrMacFinalOperation {
|
||||
EvpDigestSignFinal() {
|
||||
this.getTarget().getName() = "EVP_DigestSignFinal" and
|
||||
// Setting signature to NULL is not a final sign step but an
|
||||
// intermediary step used to get the required buffer size.
|
||||
// not tracking these calls.
|
||||
(
|
||||
exists(this.(Call).getArgument(1).getValue())
|
||||
implies
|
||||
this.(Call).getArgument(1).getValue().toInt() != 0
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestVerifyInit or EVP_DigestVerifyInit_ex.
|
||||
*/
|
||||
class EvpDigestVerifyInit extends OperationStep {
|
||||
EvpDigestVerifyInit() {
|
||||
this.getTarget().getName() in ["EVP_DigestVerifyInit", "EVP_DigestVerifyInit_ex"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = HashAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestVerifyInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
type = OsslLibContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestVerifyInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(5) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestVerifyInit" and
|
||||
result.asIndirectExpr() = this.getArgument(4) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestVerifyInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(6) and
|
||||
type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestVerifyUpdate.
|
||||
*/
|
||||
class EvpDigestVerifyUpdate extends OperationStep {
|
||||
EvpDigestVerifyUpdate() { this.getTarget().getName() = "EVP_DigestVerifyUpdate" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestVerifyFinal
|
||||
*/
|
||||
class EvpDigestVerifyFinal extends SignatureFinalOperation {
|
||||
EvpDigestVerifyFinal() { this.getTarget().getName() = "EVP_DigestVerifyFinal" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestVerify
|
||||
*/
|
||||
class EvpDigestVerify extends SignatureFinalOperation {
|
||||
EvpDigestVerify() { this.getTarget().getName() = "EVP_DigestVerify" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_verify_init`, `EVP_PKEY_verify_init_ex`,
|
||||
* `EVP_PKEY_verify_init_ex2`, or `EVP_PKEY_verify_message_init`
|
||||
* https://docs.openssl.org/master/man3/EVP_PKEY_verify/#synopsis
|
||||
*/
|
||||
class EvpVerifyInit extends OperationStep {
|
||||
EvpVerifyInit() {
|
||||
class EvpDigestAndPkeySignFinal extends EvpSignatureFinalOperation {
|
||||
EvpDigestAndPkeySignFinal() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_verify_init", "EVP_PKEY_verify_init_ex", "EVP_PKEY_verify_init_ex2",
|
||||
"EVP_PKEY_verify_message_init"
|
||||
"EVP_DigestSignFinal",
|
||||
"EVP_PKEY_sign_message_final"
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_PKEY_verify_init_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
type = OsslParamIO()
|
||||
or
|
||||
this.getTarget().getName() in ["EVP_PKEY_verify_init_ex2", "EVP_PKEY_verify_message_init"] and
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() in ["EVP_PKEY_verify_init_ex2", "EVP_PKEY_verify_message_init"] and
|
||||
result.asIndirectExpr() = this.getArgument(2) and
|
||||
type = OsslParamIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_CTX_set_signature`
|
||||
* https://docs.openssl.org/master/man3/EVP_PKEY_verify/
|
||||
*/
|
||||
class EvpCtxSetSignatureInitializer extends OperationStep {
|
||||
EvpCtxSetSignatureInitializer() { this.getTarget().getName() = "EVP_PKEY_CTX_set_signature" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_verify_message_update`.
|
||||
*/
|
||||
class EvpVerifyMessageUpdate extends OperationStep {
|
||||
EvpVerifyMessageUpdate() { this.getTarget().getName() = "EVP_PKEY_verify_message_update" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = PlaintextSizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_verify_message_final`.
|
||||
*/
|
||||
class EvpVerifyMessageFinal extends SignatureFinalOperation {
|
||||
EvpVerifyMessageFinal() { this.getTarget().getName() = "EVP_PKEY_verify_message_final" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_verify`
|
||||
*/
|
||||
class EvpVerify extends SignatureFinalOperation {
|
||||
EvpVerify() { this.getTarget().getName() = "EVP_PKEY_verify" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(4) and type = PlaintextSizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `RSA_sign` or `RSA_verify`.
|
||||
* https://docs.openssl.org/3.0/man3/RSA_sign/
|
||||
*/
|
||||
class RsaSignorVerify extends SignatureFinalOperation {
|
||||
RsaSignorVerify() { this.getTarget().getName() in ["RSA_sign", "RSA_verify"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
// Arg 0 is an NID (so asExpr not asIndirectExpr)
|
||||
result.asExpr() = this.getArgument(0) and type = HashAlgorithmIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = PlaintextSizeIO()
|
||||
or
|
||||
this.getTarget().getName() = "RSA_verify" and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
type = SignatureIO()
|
||||
or
|
||||
this.getTarget().getName() = "RSA_verify" and
|
||||
result.asIndirectExpr() = this.getArgument(4) and
|
||||
type = SignatureSizeIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(5) and type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "RSA_sign" and
|
||||
result.asDefiningArgument() = this.getArgument(3) and
|
||||
type = SignatureIO()
|
||||
or
|
||||
this.getTarget().getName() = "RSA_sign" and
|
||||
type = SignatureSizeIO() and
|
||||
result.asDefiningArgument() = this.getArgument(4)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `DSA_do_sign` or `DSA_do_verify`
|
||||
*/
|
||||
class DsaDoSignOrVerify extends SignatureFinalOperation {
|
||||
DsaDoSignOrVerify() { this.getTarget().getName() in ["DSA_do_sign", "DSA_do_verify"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = PlaintextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = PlaintextSizeIO()
|
||||
or
|
||||
this.getTarget().getName() = "DSA_do_sign" and
|
||||
result.asIndirectExpr() = this.getArgument(2) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "DSA_do_verify" and
|
||||
result.asIndirectExpr() = this.getArgument(2) and
|
||||
type = SignatureIO()
|
||||
or
|
||||
this.getTarget().getName() = "DSA_do_verify" and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
this.getTarget().getName() = "DSA_do_sign" and
|
||||
result.asIndirectExpr() = this and
|
||||
type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to `EVP_VerifyInit` or `EVP_VerifyInit_ex`
|
||||
* - int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
|
||||
* - int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type);
|
||||
*/
|
||||
class EVP_VerifyInitCall extends OperationStep {
|
||||
EVP_VerifyInitCall() { this.getTarget().getName() in ["EVP_VerifyInit", "EVP_VerifyInit_ex"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_VerifyUpdate`
|
||||
* - int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt);
|
||||
*/
|
||||
class EVP_VerifyUpdateCall extends OperationStep {
|
||||
EVP_VerifyUpdateCall() { this.getTarget().getName() = "EVP_VerifyUpdate" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = PlaintextSizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_VerifyFinal` or `EVP_VerifyFinal_ex`
|
||||
* - int EVP_VerifyFinal_ex(EVP_MD_CTX *ctx, const unsigned char *sigbuf,
|
||||
* unsigned int siglen, EVP_PKEY *pkey,
|
||||
* OSSL_LIB_CTX *libctx, const char *propq);
|
||||
*- int EVP_VerifyFinal(EVP_MD_CTX *ctx, unsigned char *sigbuf, unsigned int siglen,
|
||||
* EVP_PKEY *pkey); *
|
||||
*/
|
||||
class EVP_VerifyFinalCall extends SignatureFinalOperation {
|
||||
EVP_VerifyFinalCall() { this.getTarget().getName() in ["EVP_VerifyFinal", "EVP_VerifyFinal_ex"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = KeyIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(4) and type = OsslLibContextIO()
|
||||
// TODO: arg 5 propq?
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of a signature operation.
|
||||
* This is an OpenSSL specific class that extends the base SignatureOperationInstance.
|
||||
* An EVP signature operation instance.
|
||||
*/
|
||||
class OpenSslSignatureOperationInstance extends Crypto::SignatureOperationInstance instanceof SignatureFinalOperation
|
||||
class EvpSignatureOperationInstance extends Crypto::SignatureOperationInstance instanceof EvpSignatureFinalOperation
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
@@ -649,7 +217,7 @@ class OpenSslSignatureOperationInstance extends Crypto::SignatureOperationInstan
|
||||
* Signing, verification or unknown.
|
||||
*/
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
// NOTE: if this KeyOperationSubtype does not match initialization call's KeyOperationSubtype then we found a bug
|
||||
// TODO: if this KeyOperationSubtype does not match initialization call's KeyOperationSubtype then we found a bug
|
||||
if super.getTarget().getName().toLowerCase().matches("%sign%")
|
||||
then result instanceof Crypto::TSignMode
|
||||
else
|
||||
@@ -659,70 +227,14 @@ class OpenSslSignatureOperationInstance extends Crypto::SignatureOperationInstan
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
||||
// some signing operations may have explicit nonce generators
|
||||
super.getDominatingInitializersToStep(IVorNonceIO()).getInput(IVorNonceIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() {
|
||||
super.getDominatingInitializersToStep(SignatureIO()).getInput(SignatureIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
super.getOutputStepFlowingToStep(SignatureIO()).getOutput(SignatureIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||
super
|
||||
.getDominatingInitializersToStep(HashAlgorithmIO())
|
||||
.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
||||
or
|
||||
// Handle cases where the hash is set through the primary algorithm
|
||||
// RSA-SHA256 for example
|
||||
// NOTE: assuming the hash would not be overridden, or if it is it is undefined
|
||||
// i.e., if the above dominating initializer exists and the primary algorithm
|
||||
// specifies a hash, consider both valid hash AVCs.
|
||||
// TODO: can this behavior be build into the get dominating initializers?
|
||||
super.getPrimaryAlgorithmValueConsumer() = result and
|
||||
exists(OpenSslAlgorithmInstance i |
|
||||
i.getAvc() = result and i instanceof Crypto::HashAlgorithmInstance
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasHashAlgorithmConsumer() {
|
||||
exists(super.getDominatingInitializersToStep(HashAlgorithmIO()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for signature or MAC operation instances.
|
||||
* This is an OpenSSL specific class that extends the base SignatureOrMacOperationInstance.
|
||||
*/
|
||||
class OpenSslSignatureOrMacOperationInstance extends Crypto::SignatureOrMacOperationInstance instanceof SignatureOrMacFinalOperation
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
// TODO: some signing operations may have explicit nonce generators
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Signing, verification or unknown.
|
||||
* Keys provided in the initialization call or in a context are found by this method.
|
||||
* Keys in explicit arguments are found by overridden methods in extending classes.
|
||||
*/
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
result instanceof Crypto::TSignMode or result instanceof Crypto::TMacMode
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
||||
// some signing operations may have explicit nonce generators
|
||||
super.getDominatingInitializersToStep(IVorNonceIO()).getInput(IVorNonceIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
|
||||
}
|
||||
@@ -735,24 +247,14 @@ class OpenSslSignatureOrMacOperationInstance extends Crypto::SignatureOrMacOpera
|
||||
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: only signing operations for now, change when verificaiton is added
|
||||
*/
|
||||
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() { none() }
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||
super
|
||||
.getDominatingInitializersToStep(HashAlgorithmIO())
|
||||
.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
||||
or
|
||||
// Handle cases where the hash is set through the primary algorithm
|
||||
// RSA-SHA256 for example
|
||||
// NOTE: assuming the hash would not be overridden, or if it is it is undefined
|
||||
// i.e., if the above dominating initializer exists and the primary algorithm
|
||||
// specifies a hash, consider both valid hash AVCs.
|
||||
// TODO: can this behavior be build into the get dominating initializers?
|
||||
super.getPrimaryAlgorithmValueConsumer() = result and
|
||||
exists(OpenSslAlgorithmInstance i |
|
||||
i.getAvc() = result and i instanceof Crypto::HashAlgorithmInstance
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasHashAlgorithmConsumer() {
|
||||
exists(super.getDominatingInitializersToStep(HashAlgorithmIO()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +412,7 @@ private predicate boundFlowStepPhi(
|
||||
or
|
||||
exists(IRGuardCondition guard, boolean testIsTrue |
|
||||
guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and
|
||||
guard.controlsBranchEdge(op2.getPredecessorBlock(), op2.getUse().getBlock(), testIsTrue) and
|
||||
guard.controlsEdge(op2.getPredecessorBlock(), op2.getUse().getBlock(), testIsTrue) and
|
||||
reason = TCondReason(guard)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 6.0.2-dev
|
||||
version: 5.5.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -87,7 +87,6 @@ class ElementBase extends @element {
|
||||
*/
|
||||
class Element extends ElementBase {
|
||||
/** Gets the primary file where this element occurs. */
|
||||
pragma[nomagic]
|
||||
File getFile() { result = this.getLocation().getFile() }
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -104,9 +104,7 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
result.getStaticCallTarget().getUnderlyingCallable() = sc
|
||||
}
|
||||
|
||||
DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() }
|
||||
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() }
|
||||
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() }
|
||||
|
||||
Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
|
||||
}
|
||||
|
||||
@@ -498,9 +498,7 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
|
||||
|
||||
int getArgumentIndex() { result = p.getIndex() }
|
||||
|
||||
override FinalParameterNode getNode() {
|
||||
finalParameterNodeHasParameterAndIndex(result, p, indirectionIndex)
|
||||
}
|
||||
override Node getNode() { finalParameterNodeHasParameterAndIndex(result, p, indirectionIndex) }
|
||||
|
||||
override int getIndirection() { result = indirectionIndex + 1 }
|
||||
|
||||
@@ -1002,7 +1000,7 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
result instanceof FalseEdge
|
||||
}
|
||||
|
||||
class GuardValue = IRGuards::GuardValue;
|
||||
class GuardValue = Boolean;
|
||||
|
||||
class Guard instanceof IRGuards::IRGuardCondition {
|
||||
string toString() { result = super.toString() }
|
||||
@@ -1010,7 +1008,7 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
predicate hasValueBranchEdge(IRCfg::BasicBlock bb1, IRCfg::BasicBlock bb2, GuardValue branch) {
|
||||
exists(EdgeKind kind |
|
||||
super.getBlock() = bb1 and
|
||||
kind = getConditionalEdge(branch.asBooleanValue()) and
|
||||
kind = getConditionalEdge(branch) and
|
||||
bb1.getSuccessor(kind) = bb2
|
||||
)
|
||||
}
|
||||
@@ -1023,7 +1021,7 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, IRCfg::BasicBlock bb, GuardValue branch) {
|
||||
guard.(IRGuards::IRGuardCondition).valueControls(bb, branch)
|
||||
guard.(IRGuards::IRGuardCondition).controls(bb, branch)
|
||||
}
|
||||
|
||||
predicate keepAllPhiInputBackEdges() { any() }
|
||||
@@ -1050,35 +1048,25 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate guardChecksInstr(
|
||||
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, boolean branch,
|
||||
int indirectionIndex
|
||||
private predicate guardChecks(
|
||||
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def,
|
||||
DataFlowIntegrationInput::GuardValue branch, int indirectionIndex
|
||||
) {
|
||||
exists(Node node |
|
||||
nodeHasInstruction(node, instr, indirectionIndex) and
|
||||
guardChecksNode(g, node, branch, indirectionIndex)
|
||||
exists(UseImpl use |
|
||||
guardChecksNode(g, use.getNode(), branch, indirectionIndex) and
|
||||
ssaDefReachesCertainUse(def, use)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate guardChecksWithWrappers(
|
||||
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val,
|
||||
int indirectionIndex
|
||||
) {
|
||||
IRGuards::Guards_v1::ValidationWrapperWithState<int, guardChecksInstr/4>::guardChecksDef(g, def,
|
||||
val, indirectionIndex)
|
||||
}
|
||||
|
||||
Node getABarrierNode(int indirectionIndex) {
|
||||
// Only get the SynthNodes from the shared implementation, as the ExprNodes cannot
|
||||
// be matched on SourceVariable.
|
||||
result.(SsaSynthNode).getSynthNode() =
|
||||
DataFlowIntegrationImpl::BarrierGuardDefWithState<int, guardChecksWithWrappers/4>::getABarrierNode(indirectionIndex)
|
||||
DataFlowIntegrationImpl::BarrierGuardDefWithState<int, guardChecks/4>::getABarrierNode(indirectionIndex)
|
||||
or
|
||||
// Calculate the guarded UseImpls corresponding to ExprNodes directly.
|
||||
exists(
|
||||
DataFlowIntegrationInput::Guard g, IRGuards::GuardValue branch, Definition def, IRBlock bb
|
||||
|
|
||||
guardChecksWithWrappers(g, def, branch, indirectionIndex) and
|
||||
exists(DataFlowIntegrationInput::Guard g, boolean branch, Definition def, IRBlock bb |
|
||||
guardChecks(g, def, branch, indirectionIndex) and
|
||||
exists(UseImpl use |
|
||||
ssaDefReachesCertainUse(def, use) and
|
||||
use.getBlock() = bb and
|
||||
@@ -1136,15 +1124,7 @@ predicate ssaFlow(Node nodeFrom, Node nodeTo) {
|
||||
*/
|
||||
class PhiNode extends Definition instanceof SsaImpl::PhiNode {
|
||||
/** Gets a definition that is an input to this phi node. */
|
||||
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
||||
|
||||
/**
|
||||
* Holds if `input` is an input to this phi node along the edge originating
|
||||
* in `bb`.
|
||||
*/
|
||||
final predicate hasInputFromBlock(Definition input, IRBlock bb) {
|
||||
phiHasInputFromBlock(this, input, bb)
|
||||
}
|
||||
final Definition getAnInput() { phiHasInputFromBlock(this, result, _) }
|
||||
}
|
||||
|
||||
/** An static single assignment (SSA) definition. */
|
||||
@@ -1169,53 +1149,10 @@ class Definition extends SsaImpl::Definition {
|
||||
exists(SourceVariable sv, IRBlock bb, int i, UseImpl use |
|
||||
ssaDefReachesRead(sv, this, bb, i) and
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
use = TDirectUseImpl(result, 0)
|
||||
result = use.getNode().asOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition defines the parameter `p` upon entry into the
|
||||
* enclosing function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isParameterDefinition(Parameter p) {
|
||||
this.getIndirectionIndex() = 0 and
|
||||
getDefImpl(this).getValue().asInstruction().(InitializeParameterInstruction).getParameter() = p
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition defines the `indirectionIndex`'th indirection of
|
||||
* parameter `p` upon entry into the enclosing function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isIndirectParameterDefinition(Parameter p, int indirectionIndex) {
|
||||
this.getIndirectionIndex() = indirectionIndex and
|
||||
indirectionIndex > 0 and
|
||||
getDefImpl(this).getValue().asInstruction().(InitializeParameterInstruction).getParameter() = p
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition defines the implicit `this` parameter upon entry into
|
||||
* the enclosing member function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isThisDefinition() {
|
||||
this.getIndirectionIndex() = 0 and
|
||||
getDefImpl(this).getValue().asInstruction().(InitializeParameterInstruction).hasIndex(-1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition defines the implicit `*this` parameter (i.e., the
|
||||
* indirection of the `this` parameter) upon entry into the enclosing member
|
||||
* function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isIndirectThisDefinition(int indirectionIndex) {
|
||||
this.getIndirectionIndex() = indirectionIndex and
|
||||
indirectionIndex > 0 and
|
||||
getDefImpl(this).getValue().asInstruction().(InitializeParameterInstruction).hasIndex(-1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `Operand` that represents an indirect use of this definition.
|
||||
*
|
||||
@@ -1230,11 +1167,10 @@ class Definition extends SsaImpl::Definition {
|
||||
* value that was defined by the definition.
|
||||
*/
|
||||
Operand getAnIndirectUse(int indirectionIndex) {
|
||||
indirectionIndex > 0 and
|
||||
exists(SourceVariable sv, IRBlock bb, int i, UseImpl use |
|
||||
ssaDefReachesRead(sv, this, bb, i) and
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
use = TDirectUseImpl(result, indirectionIndex)
|
||||
result = use.getNode().asIndirectOperand(indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -52,18 +52,11 @@ class GotoEdge extends EdgeKindImpl, TGotoEdge {
|
||||
final override string toString() { result = "Goto" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A "true" or "false" edge representing a successor of a conditional branch.
|
||||
*/
|
||||
abstract private class BooleanEdgeKindImpl extends EdgeKindImpl { }
|
||||
|
||||
final class BooleanEdge = BooleanEdgeKindImpl;
|
||||
|
||||
/**
|
||||
* A "true" edge, representing the successor of a conditional branch when the
|
||||
* condition is non-zero.
|
||||
*/
|
||||
class TrueEdge extends BooleanEdgeKindImpl, TTrueEdge {
|
||||
class TrueEdge extends EdgeKindImpl, TTrueEdge {
|
||||
final override string toString() { result = "True" }
|
||||
}
|
||||
|
||||
@@ -71,7 +64,7 @@ class TrueEdge extends BooleanEdgeKindImpl, TTrueEdge {
|
||||
* A "false" edge, representing the successor of a conditional branch when the
|
||||
* condition is zero.
|
||||
*/
|
||||
class FalseEdge extends BooleanEdgeKindImpl, TFalseEdge {
|
||||
class FalseEdge extends EdgeKindImpl, TFalseEdge {
|
||||
final override string toString() { result = "False" }
|
||||
}
|
||||
|
||||
@@ -102,48 +95,19 @@ class SehExceptionEdge extends ExceptionEdgeImpl, TSehExceptionEdge {
|
||||
final override string toString() { result = "SEH Exception" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An edge from a `Switch` instruction to one of the cases, or to the default
|
||||
* branch.
|
||||
*/
|
||||
abstract private class SwitchEdgeKindImpl extends EdgeKindImpl {
|
||||
/**
|
||||
* Gets the smallest value of the switch expression for which control will flow along this edge.
|
||||
*/
|
||||
string getMinValue() { none() }
|
||||
|
||||
/**
|
||||
* Gets the largest value of the switch expression for which control will flow along this edge.
|
||||
*/
|
||||
string getMaxValue() { none() }
|
||||
|
||||
/**
|
||||
* Gets the unique value of the switch expression for which control will
|
||||
* flow along this edge, if any.
|
||||
*/
|
||||
final string getValue() { result = unique( | | [this.getMinValue(), this.getMaxValue()]) }
|
||||
|
||||
/** Holds if this edge is the default edge. */
|
||||
predicate isDefault() { none() }
|
||||
}
|
||||
|
||||
final class SwitchEdge = SwitchEdgeKindImpl;
|
||||
|
||||
/**
|
||||
* A "default" edge, representing the successor of a `Switch` instruction when
|
||||
* none of the case values matches the condition value.
|
||||
*/
|
||||
class DefaultEdge extends SwitchEdgeKindImpl, TDefaultEdge {
|
||||
class DefaultEdge extends EdgeKindImpl, TDefaultEdge {
|
||||
final override string toString() { result = "Default" }
|
||||
|
||||
final override predicate isDefault() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A "case" edge, representing the successor of a `Switch` instruction when the
|
||||
* the condition value matches a corresponding `case` label.
|
||||
*/
|
||||
class CaseEdge extends SwitchEdgeKindImpl, TCaseEdge {
|
||||
class CaseEdge extends EdgeKindImpl, TCaseEdge {
|
||||
string minValue;
|
||||
string maxValue;
|
||||
|
||||
@@ -155,9 +119,24 @@ class CaseEdge extends SwitchEdgeKindImpl, TCaseEdge {
|
||||
else result = "Case[" + minValue + ".." + maxValue + "]"
|
||||
}
|
||||
|
||||
final override string getMinValue() { result = minValue }
|
||||
/**
|
||||
* Gets the smallest value of the switch expression for which control will flow along this edge.
|
||||
*/
|
||||
final string getMinValue() { result = minValue }
|
||||
|
||||
final override string getMaxValue() { result = maxValue }
|
||||
/**
|
||||
* Gets the largest value of the switch expression for which control will flow along this edge.
|
||||
*/
|
||||
final string getMaxValue() { result = maxValue }
|
||||
|
||||
/**
|
||||
* Gets the unique value of the switch expression for which control will
|
||||
* flow along this edge, if any.
|
||||
*/
|
||||
final string getValue() {
|
||||
minValue = maxValue and
|
||||
result = minValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1084,12 +1084,6 @@ class BinaryInstruction extends Instruction {
|
||||
or
|
||||
op1 = this.getRightOperand() and op2 = this.getLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the left or right
|
||||
* operand of this binary instruction.
|
||||
*/
|
||||
Instruction getAnInput() { result = this.getLeft() or result = this.getRight() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,14 +129,12 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -146,7 +144,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -156,7 +154,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -164,7 +162,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -173,7 +171,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -184,7 +182,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -208,7 +206,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -231,7 +229,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -244,7 +242,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -256,7 +254,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -279,7 +277,8 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -295,8 +294,10 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,64 +311,68 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1084,12 +1084,6 @@ class BinaryInstruction extends Instruction {
|
||||
or
|
||||
op1 = this.getRightOperand() and op2 = this.getLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the left or right
|
||||
* operand of this binary instruction.
|
||||
*/
|
||||
Instruction getAnInput() { result = this.getLeft() or result = this.getRight() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,14 +129,12 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -146,7 +144,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -156,7 +154,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -164,7 +162,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -173,7 +171,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -184,7 +182,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -208,7 +206,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -231,7 +229,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -244,7 +242,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -256,7 +254,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -279,7 +277,8 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -295,8 +294,10 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,64 +311,68 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1084,12 +1084,6 @@ class BinaryInstruction extends Instruction {
|
||||
or
|
||||
op1 = this.getRightOperand() and op2 = this.getLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the left or right
|
||||
* operand of this binary instruction.
|
||||
*/
|
||||
Instruction getAnInput() { result = this.getLeft() or result = this.getRight() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user