Compare commits

..

1 Commits

Author SHA1 Message Date
idrissrio
fac2beac13 Java: remove isImplict() 2025-09-08 08:16:49 +02:00
2747 changed files with 63836 additions and 153281 deletions

4
.github/copilot-instructions.md vendored Normal file
View 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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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
View File

@@ -76,6 +76,3 @@ node_modules/
# some upgrade/downgrade checks create these files
**/upgrades/*/*.dbscheme.stats
**/downgrades/*/*.dbscheme.stats
# Mergetool files
*.orig

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -10,3 +10,4 @@ members = [
"rust/ast-generator",
"rust/autobuild",
]
exclude = ["mad-generation-build"]

View File

@@ -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")

View File

@@ -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

View File

@@ -1,10 +0,0 @@
{
"paths": [
".github/workflows/*.yml",
".github/workflows/*.yaml",
".github/reusable_workflows/**/*.yml",
".github/reusable_workflows/**/*.yaml",
"**/action.yml",
"**/action.yaml"
]
}

View File

@@ -1,2 +0,0 @@
@echo off
type "%CODEQL_EXTRACTOR_ACTIONS_ROOT%\tools\baseline-config.json"

View File

@@ -1,3 +0,0 @@
#!/bin/sh
cat "$CODEQL_EXTRACTOR_ACTIONS_ROOT/tools/baseline-config.json"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -1,3 +0,0 @@
## 0.4.17
No user-facing changes.

View File

@@ -1,3 +0,0 @@
## 0.4.18
No user-facing changes.

View File

@@ -1,3 +0,0 @@
## 0.4.19
No user-facing changes.

View File

@@ -1,3 +0,0 @@
## 0.4.20
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.4.20
lastReleaseVersion: 0.4.16

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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. */

View File

@@ -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. */

View File

@@ -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. */

View File

@@ -1,5 +1,5 @@
name: codeql/actions-all
version: 0.4.21-dev
version: 0.4.17-dev
library: true
warnOnImplicitThis: true
dependencies:

View File

@@ -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.

View File

@@ -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, ""

View File

@@ -26,6 +26,8 @@ private module MyConfig implements DataFlow::ConfigSig {
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
}
module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -36,6 +36,8 @@ private module MyConfig implements DataFlow::ConfigSig {
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
}
module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -27,6 +27,8 @@ private module MyConfig implements DataFlow::ConfigSig {
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
}
module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -26,6 +26,8 @@ private module MyConfig implements DataFlow::ConfigSig {
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
}
module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -36,6 +36,8 @@ private module MyConfig implements DataFlow::ConfigSig {
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
}
module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -27,6 +27,8 @@ private module MyConfig implements DataFlow::ConfigSig {
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
}
module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -1,3 +0,0 @@
## 0.6.10
No user-facing changes.

View File

@@ -1,3 +0,0 @@
## 0.6.11
No user-facing changes.

View File

@@ -1,3 +0,0 @@
## 0.6.12
No user-facing changes.

View File

@@ -1,5 +0,0 @@
## 0.6.9
### Minor Analysis Improvements
* Actions analysis now reports file coverage information on the CodeQL status page.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.6.12
lastReleaseVersion: 0.6.8

View File

@@ -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()

View File

@@ -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]

View File

@@ -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 }} |

View File

@@ -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

View File

@@ -9,7 +9,6 @@
"fragments": [
"/*- Compilations -*/",
"/*- External data -*/",
"/*- Overlay support -*/",
"/*- Files and folders -*/",
"/*- Diagnostic messages -*/",
"/*- Diagnostic messages: severity -*/",

View File

@@ -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

View File

@@ -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

View 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`.

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The predicate `getAContructorCall` in the class `SslContextClass` has been deprecated. Use `getAConstructorCall` instead.

View File

@@ -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`.

View File

@@ -1,3 +0,0 @@
## 5.6.1
No user-facing changes.

View File

@@ -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.

View File

@@ -1,3 +0,0 @@
## 6.0.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 6.0.1
lastReleaseVersion: 5.5.0

View File

@@ -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

View File

@@ -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) }

View File

@@ -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)
)

View File

@@ -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 }

View File

@@ -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(), _,
_)

View File

@@ -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()

View File

@@ -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)
)

View File

@@ -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"
}
/**

View File

@@ -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() }
}

View File

@@ -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
}
}

View File

@@ -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)
)

View File

@@ -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)
)
}

View File

@@ -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
}

View File

@@ -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)
)
}

View File

@@ -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)
}
}

View File

@@ -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)
)
}

View File

@@ -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)
)
}

View File

@@ -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)
)
)
}

View File

@@ -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)
}

View File

@@ -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 ?
)
}

View File

@@ -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 }
}

View File

@@ -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>;

View File

@@ -4,5 +4,4 @@ module OpenSslModel {
import Operations.OpenSSLOperations
import Random
import GenericSourceCandidateLiteral
import ArtifactPassthrough
}

View File

@@ -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

View File

@@ -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() }

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()))
}
}

View File

@@ -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)
)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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() }
}

View File

@@ -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)
)
}

View File

@@ -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
}
}
/**

View File

@@ -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() }
}
/**

View File

@@ -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())
)
}

View File

@@ -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() }
}
/**

View File

@@ -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())
)
}

View File

@@ -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