mirror of
https://github.com/github/codeql.git
synced 2026-05-30 11:01:24 +02:00
Compare commits
5 Commits
mbg/go/dep
...
redsun82/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
956209f5c9 | ||
|
|
4079db755d | ||
|
|
fff267075c | ||
|
|
a3569f5543 | ||
|
|
589fbd35cf |
11
.github/dependabot.yml
vendored
11
.github/dependabot.yml
vendored
@@ -25,11 +25,18 @@ updates:
|
||||
allow:
|
||||
- dependency-name: "golang.org/x/mod"
|
||||
- dependency-name: "golang.org/x/tools"
|
||||
exclude-paths:
|
||||
- "go/ql/**"
|
||||
groups:
|
||||
extractor-dependencies:
|
||||
patterns:
|
||||
- "golang.org/x/*"
|
||||
reviewers:
|
||||
- "github/codeql-go"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "go/ql/test"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
reviewers:
|
||||
- "github/codeql-go"
|
||||
|
||||
2
.github/workflows/query-list.yml
vendored
2
.github/workflows/query-list.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
|
||||
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
|
||||
uses: ./codeql/.github/actions/fetch-codeql
|
||||
- name: Build code scanning query list
|
||||
run: |
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -76,6 +76,3 @@ node_modules/
|
||||
# some upgrade/downgrade checks create these files
|
||||
**/upgrades/*/*.dbscheme.stats
|
||||
**/downgrades/*/*.dbscheme.stats
|
||||
|
||||
# Mergetool files
|
||||
*.orig
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# Catch-all for anything which isn't matched by a line lower down
|
||||
* @github/code-scanning-alert-coverage
|
||||
|
||||
# CodeQL language libraries
|
||||
/actions/ @github/codeql-dynamic
|
||||
/cpp/ @github/codeql-c-analysis
|
||||
/csharp/ @github/codeql-csharp
|
||||
@@ -11,10 +7,8 @@
|
||||
/java/ @github/codeql-java
|
||||
/javascript/ @github/codeql-javascript
|
||||
/python/ @github/codeql-python
|
||||
/ql/ @github/codeql-ql-for-ql-reviewers
|
||||
/ruby/ @github/codeql-ruby
|
||||
/rust/ @github/codeql-rust
|
||||
/shared/ @github/codeql-shared-libraries-reviewers
|
||||
/swift/ @github/codeql-swift
|
||||
/misc/codegen/ @github/codeql-swift
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||
@@ -31,6 +25,9 @@
|
||||
/docs/codeql/ql-language-reference/ @github/codeql-frontend-reviewers
|
||||
/docs/query-*-style-guide.md @github/codeql-analysis-reviewers
|
||||
|
||||
# QL for QL reviewers
|
||||
/ql/ @github/codeql-ql-for-ql-reviewers
|
||||
|
||||
# Bazel (excluding BUILD.bazel files)
|
||||
MODULE.bazel @github/codeql-ci-reviewers
|
||||
.bazelversion @github/codeql-ci-reviewers
|
||||
|
||||
763
Cargo.lock
generated
763
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
70
MODULE.bazel
70
MODULE.bazel
@@ -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",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
name: "actions"
|
||||
aliases: []
|
||||
display_name: "GitHub Actions"
|
||||
version: 0.0.1
|
||||
column_kind: "utf16"
|
||||
@@ -7,11 +8,9 @@ build_modes:
|
||||
- none
|
||||
default_queries:
|
||||
- codeql/actions-queries
|
||||
# Actions workflows are not reported separately by the GitHub API, so we can't
|
||||
# associate them with a specific language.
|
||||
file_coverage_languages: []
|
||||
github_api_languages: []
|
||||
scc_languages:
|
||||
- YAML
|
||||
scc_languages: []
|
||||
file_types:
|
||||
- name: workflow
|
||||
display_name: GitHub Actions workflow files
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"paths": [
|
||||
".github/workflows/*.yml",
|
||||
".github/workflows/*.yaml",
|
||||
".github/reusable_workflows/**/*.yml",
|
||||
".github/reusable_workflows/**/*.yaml",
|
||||
"**/action.yml",
|
||||
"**/action.yaml"
|
||||
]
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
type "%CODEQL_EXTRACTOR_ACTIONS_ROOT%\tools\baseline-config.json"
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat "$CODEQL_EXTRACTOR_ACTIONS_ROOT/tools/baseline-config.json"
|
||||
@@ -1,4 +1,3 @@
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-094/CodeInjectionCritical.ql
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
ql/actions/ql/src/Debug/SyntaxError.ql
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionMedium.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionMedium.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
## 0.4.18
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.17
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.16
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.17
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.18
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.18
|
||||
lastReleaseVersion: 0.4.16
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.19-dev
|
||||
version: 0.4.17-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
## 0.6.10
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Actions analysis now reports file coverage information on the CodeQL status page.
|
||||
|
||||
## 0.6.8
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* @id actions/diagnostics/successfully-extracted-files
|
||||
* @name Extracted files
|
||||
* @description List all files that were extracted.
|
||||
* @kind diagnostic
|
||||
* @tags successfully-extracted-files
|
||||
*/
|
||||
|
||||
private import codeql.Locations
|
||||
|
||||
from File f
|
||||
where exists(f.getRelativePath())
|
||||
select f, ""
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
- run: |
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
- run: |
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
- run: |
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.10
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.6.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Actions analysis now reports file coverage information on the CodeQL status page.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.10
|
||||
lastReleaseVersion: 0.6.8
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.11-dev
|
||||
version: 0.6.9-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -7,10 +7,12 @@ ql/cpp/ql/src/Diagnostics/ExtractedFiles.ql
|
||||
ql/cpp/ql/src/Diagnostics/ExtractionWarnings.ql
|
||||
ql/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
|
||||
@@ -28,6 +30,7 @@ ql/cpp/ql/src/Security/CWE/CWE-120/VeryLikelyOverrunWrite.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
|
||||
@@ -40,6 +43,7 @@ ql/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfUniquePointerAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-611/XXE.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql
|
||||
|
||||
@@ -1,17 +1,3 @@
|
||||
## 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
|
||||
|
||||
@@ -35,7 +35,7 @@ class CustomOptions extends Options {
|
||||
override predicate returnsNull(Call call) { Options.super.returnsNull(call) }
|
||||
|
||||
/**
|
||||
* Holds if a call to the function `f` will never return.
|
||||
* Holds if a call to this function will never return.
|
||||
*
|
||||
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
||||
* `longjmp`, `error`, `__builtin_unreachable` and any function with a
|
||||
|
||||
4
cpp/ql/lib/change-notes/2025-09-02-vla.md
Normal file
4
cpp/ql/lib/change-notes/2025-09-02-vla.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type defined in terms of an other `VlaDeclStmt` via a `typedef`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* 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`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* The C/C++ "build-mode: none" support is now General Availability (GA).
|
||||
@@ -1,9 +0,0 @@
|
||||
## 5.6.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The predicate `getAContructorCall` in the class `SslContextClass` has been deprecated. Use `getAConstructorCall` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type is defined in terms of another `VlaDeclStmt` via a `typedef`.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 5.6.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 5.6.1
|
||||
lastReleaseVersion: 5.5.0
|
||||
|
||||
@@ -127,7 +127,7 @@ abstract class CryptographicAlgorithm extends CryptographicArtifact {
|
||||
/**
|
||||
* Normalizes a raw name into a normalized name as found in `CryptoAlgorithmNames.qll`.
|
||||
* Subclassess should override for more api-specific normalization.
|
||||
* By default, converts a raw name to upper-case with no hyphen, underscore, hash, or space.
|
||||
* By deafult, converts a raw name to upper-case with no hyphen, underscore, hash, or space.
|
||||
*/
|
||||
bindingset[s]
|
||||
string normalizeName(string s) {
|
||||
|
||||
@@ -652,14 +652,14 @@ module KeyGeneration {
|
||||
* Trace from EVP_PKEY_CTX* at algorithm sink to keygen,
|
||||
* users can then extrapolatae the matching algorithm from the alg sink to the keygen
|
||||
*/
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSizeConfig implements DataFlow::ConfigSig {
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isEVP_PKEY_CTX_Source(source, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isKeyGen_EVP_PKEY_CTX_Sink(sink, _) }
|
||||
}
|
||||
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize_Flow =
|
||||
DataFlow::Global<EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSizeConfig>;
|
||||
DataFlow::Global<EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize>;
|
||||
|
||||
/**
|
||||
* UNKNOWN key sizes to general purpose key generation functions (i.e., that take in no key size and assume
|
||||
|
||||
@@ -59,7 +59,7 @@ private string privateNormalizeFunctionName(Function f, string algType) {
|
||||
*
|
||||
* The predicate attempts to restrict normalization to what looks like an openssl
|
||||
* library by looking for functions only in an openssl path (see `isPossibleOpenSSLFunction`).
|
||||
* This may give false positive functions if a directory erronously appears to be openssl;
|
||||
* This may give false postive functions if a directory erronously appears to be openssl;
|
||||
* however, we take the stance that if a function
|
||||
* exists strongly mapping to a known function name in a directory such as these,
|
||||
* regardless of whether its actually a part of openSSL or not, we will analyze it as though it were.
|
||||
|
||||
@@ -49,7 +49,7 @@ private string privateNormalizeFunctionName(Function f, string algType) {
|
||||
*
|
||||
* The predicate attempts to restrict normalization to what looks like an openssl
|
||||
* library by looking for functions only in an openssl path (see `isPossibleOpenSSLFunction`).
|
||||
* This may give false positive functions if a directory erronously appears to be openssl;
|
||||
* This may give false postive functions if a directory erronously appears to be openssl;
|
||||
* however, we take the stance that if a function
|
||||
* exists strongly mapping to a known function name in a directory such as these,
|
||||
* regardless of whether its actually a part of openSSL or not, we will analyze it as though it were.
|
||||
|
||||
@@ -31,7 +31,7 @@ predicate knownPassthroughFunction(Function f, int inInd, int outInd) {
|
||||
|
||||
/**
|
||||
* `c` is a call to a function that preserves the algorithm but changes its form.
|
||||
* `inExpr` is the input argument passing through to, `outExpr` is the next expression in a dataflow step associated with `c`
|
||||
* `onExpr` is the input argument passing through to, `outExpr` is the next expression in a dataflow step associated with `c`
|
||||
*/
|
||||
predicate knownPassthoughCall(Call c, Expr inExpr, Expr outExpr) {
|
||||
exists(int inInd, int outInd |
|
||||
|
||||
@@ -14,8 +14,8 @@ module CryptoInput implements InputSig<Language::Location> {
|
||||
result = node.asExpr() or
|
||||
result = node.asParameter() or
|
||||
result = node.asVariable() or
|
||||
result = node.asDefiningArgument() or
|
||||
result = node.asIndirectExpr()
|
||||
result = node.asDefiningArgument()
|
||||
// TODO: do we need asIndirectExpr()?
|
||||
}
|
||||
|
||||
string locationToFileBaseNameAndLineNumberString(Location location) {
|
||||
@@ -53,7 +53,7 @@ module ArtifactFlowConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
}
|
||||
|
||||
module ArtifactFlow = TaintTracking::Global<ArtifactFlowConfig>;
|
||||
module ArtifactFlow = DataFlow::Global<ArtifactFlowConfig>;
|
||||
|
||||
/**
|
||||
* An artifact output to node input configuration
|
||||
@@ -93,13 +93,7 @@ module GenericDataSourceFlow = TaintTracking::Global<GenericDataSourceFlowConfig
|
||||
|
||||
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof OpenSslGenericSourceCandidateLiteral
|
||||
{
|
||||
override DataFlow::Node getOutputNode() {
|
||||
// OpenSSL algorithms may be referenced either by string name or by numeric ID:
|
||||
// String names (e.g. "AES-256-CBC") appear in the AST as character pointer
|
||||
// literals. For these we must use `asIndirectExpr`. Numeric IDs (e.g. NID_aes_256_cbc)
|
||||
// appear as integer literals. For these, we must use `asExpr` to get the "value" node.
|
||||
[result.asIndirectExpr(), result.asExpr()] = this
|
||||
}
|
||||
override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
// TODO: separate config to avoid blowing up data-flow analysis
|
||||
@@ -109,4 +103,28 @@ private class ConstantDataSource extends Crypto::GenericConstantSourceInstance i
|
||||
override string getAdditionalDescription() { result = this.toString() }
|
||||
}
|
||||
|
||||
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::ArtifactInstance artifact).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(Crypto::FlowAwareElement other).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
}
|
||||
}
|
||||
|
||||
module ArtifactUniversalFlow = DataFlow::Global<ArtifactUniversalFlowConfig>;
|
||||
|
||||
import OpenSSL.OpenSSL
|
||||
|
||||
@@ -14,13 +14,9 @@ private import PaddingAlgorithmInstance
|
||||
*/
|
||||
module KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
(
|
||||
source.asExpr() instanceof KnownOpenSslAlgorithmExpr or
|
||||
source.asIndirectExpr() instanceof KnownOpenSslAlgorithmExpr
|
||||
) and
|
||||
source.asExpr() instanceof KnownOpenSslAlgorithmExpr and
|
||||
// No need to flow direct operations to AVCs
|
||||
not source.asExpr() instanceof OpenSslDirectAlgorithmOperationCall and
|
||||
not source.asIndirectExpr() instanceof OpenSslDirectAlgorithmOperationCall
|
||||
not source.asExpr() instanceof OpenSslDirectAlgorithmOperationCall
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
@@ -50,12 +46,10 @@ module KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::
|
||||
}
|
||||
|
||||
module KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow =
|
||||
TaintTracking::Global<KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig>;
|
||||
DataFlow::Global<KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig>;
|
||||
|
||||
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof OpenSslSpecialPaddingLiteral
|
||||
}
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof OpenSslPaddingLiteral }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(PaddingAlgorithmValueConsumer c | c.getInputNode() = sink)
|
||||
@@ -67,7 +61,7 @@ module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataF
|
||||
}
|
||||
|
||||
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
|
||||
TaintTracking::Global<RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
|
||||
DataFlow::Global<RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
|
||||
|
||||
class OpenSslAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep {
|
||||
OpenSslAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) }
|
||||
|
||||
@@ -53,8 +53,7 @@ class KnownOpenSslBlockModeConstantAlgorithmInstance extends OpenSslAlgorithmIns
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
|
||||
@@ -2,10 +2,12 @@ import cpp
|
||||
private import experimental.quantum.Language
|
||||
private import KnownAlgorithmConstants
|
||||
private import Crypto::KeyOpAlg as KeyOpAlg
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import OpenSSLAlgorithmInstances
|
||||
private import OpenSSLAlgorithmInstanceBase
|
||||
private import PaddingAlgorithmInstance
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import AlgToAVCFlow
|
||||
private import BlockAlgorithmInstance
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSslCipherAlgorithmExpr`, converts this to a cipher family type.
|
||||
@@ -77,8 +79,7 @@ class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstan
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
@@ -96,13 +97,10 @@ class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstan
|
||||
}
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() {
|
||||
//TODO: the padding is either self, or it flows through getter ctx to a set padding call
|
||||
// like EVP_PKEY_CTX_set_rsa_padding
|
||||
result = this
|
||||
or
|
||||
exists(OperationStep s |
|
||||
this.getAvc().(AvcContextCreationStep).flowsToOperationStep(s) and
|
||||
s.getAlgorithmValueConsumerForInput(PaddingAlgorithmIO()) =
|
||||
result.(OpenSslAlgorithmInstance).getAvc()
|
||||
)
|
||||
// TODO or trace through getter ctx to set padding
|
||||
}
|
||||
|
||||
override string getRawAlgorithmName() {
|
||||
@@ -119,7 +117,7 @@ class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstan
|
||||
knownOpenSslConstantToCipherFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSslConstantToCipherFamilyType(this, _) and
|
||||
result = Crypto::KeyOpAlg::TOtherKeyOperationAlgorithmType()
|
||||
result = Crypto::KeyOpAlg::TUnknownKeyOperationAlgorithmType()
|
||||
}
|
||||
|
||||
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
|
||||
|
||||
@@ -21,8 +21,7 @@ class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorith
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -37,8 +37,7 @@ class KnownOpenSslKeyAgreementConstantAlgorithmInstance extends OpenSslAlgorithm
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
|
||||
@@ -171,15 +171,9 @@ class KnownOpenSslKeyAgreementAlgorithmExpr extends Expr instanceof KnownOpenSsl
|
||||
}
|
||||
|
||||
predicate knownOpenSslAlgorithmOperationCall(Call c, string normalized, string algType) {
|
||||
c.getTarget().getName() in [
|
||||
"EVP_RSA_gen", "RSA_generate_key_ex", "RSA_generate_key", "RSA_new", "RSA_sign", "RSA_verify"
|
||||
] and
|
||||
c.getTarget().getName() in ["EVP_RSA_gen", "RSA_generate_key_ex", "RSA_generate_key", "RSA_new"] and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
or
|
||||
c.getTarget().getName() in ["DSA_do_sign", "DSA_do_verify"] and
|
||||
normalized = "DSA" and
|
||||
algType = "SIGNATURE"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,13 +2,12 @@ import cpp
|
||||
private import experimental.quantum.Language
|
||||
private import KnownAlgorithmConstants
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
||||
private import Crypto::KeyOpAlg as KeyOpAlg
|
||||
private import AlgToAVCFlow
|
||||
|
||||
class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::KeyOperationAlgorithmInstance instanceof KnownOpenSslMacAlgorithmExpr
|
||||
Crypto::MacAlgorithmInstance instanceof KnownOpenSslMacAlgorithmExpr
|
||||
{
|
||||
OpenSslAlgorithmValueConsumer getterCall;
|
||||
|
||||
@@ -22,8 +21,7 @@ class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
@@ -35,34 +33,17 @@ class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
|
||||
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
|
||||
|
||||
override string getRawAlgorithmName() {
|
||||
override string getRawMacAlgorithmName() {
|
||||
result = this.(Literal).getValue().toString()
|
||||
or
|
||||
result = this.(Call).getTarget().getName()
|
||||
}
|
||||
|
||||
override Crypto::KeyOpAlg::AlgorithmType getAlgorithmType() {
|
||||
if this instanceof KnownOpenSslHMacAlgorithmExpr
|
||||
then result = KeyOpAlg::TMac(KeyOpAlg::HMAC())
|
||||
else
|
||||
if this instanceof KnownOpenSslCMacAlgorithmExpr
|
||||
then result = KeyOpAlg::TMac(KeyOpAlg::CMAC())
|
||||
else result = KeyOpAlg::TMac(KeyOpAlg::OtherMacAlgorithmType())
|
||||
override Crypto::MacType getMacType() {
|
||||
this instanceof KnownOpenSslHMacAlgorithmExpr and result = Crypto::HMAC()
|
||||
or
|
||||
this instanceof KnownOpenSslCMacAlgorithmExpr and result = Crypto::CMAC()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
|
||||
// TODO: trace to any key size initializer?
|
||||
none()
|
||||
}
|
||||
|
||||
override int getKeySizeFixed() {
|
||||
// TODO: are there known fixed key sizes to consider?
|
||||
none()
|
||||
}
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { none() }
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
|
||||
}
|
||||
|
||||
class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HmacAlgorithmInstance,
|
||||
@@ -79,13 +60,9 @@ class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HmacAlgorithmIns
|
||||
// where the current AVC traces to a HashAlgorithmIO consuming operation step.
|
||||
// TODO: need to consider getting reset values, tracing down to the first set for now
|
||||
exists(OperationStep s, AvcContextCreationStep avc |
|
||||
avc = super.getAvc() and
|
||||
avc = this.getAvc() and
|
||||
avc.flowsToOperationStep(s) and
|
||||
s.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
||||
)
|
||||
}
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { none() }
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import cpp
|
||||
private import experimental.quantum.Language
|
||||
private import OpenSSLAlgorithmInstanceBase
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
private import AlgToAVCFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as KeyOpAlg
|
||||
|
||||
/**
|
||||
@@ -18,14 +18,13 @@ private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as K
|
||||
* # define RSA_PKCS1_WITH_TLS_PADDING 7
|
||||
* # define RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING 8
|
||||
*/
|
||||
class OpenSslSpecialPaddingLiteral extends Literal {
|
||||
class OpenSslPaddingLiteral extends Literal {
|
||||
// TODO: we can be more specific about where the literal is in a larger expression
|
||||
// to avoid literals that are clealy not representing an algorithm, e.g., array indices.
|
||||
OpenSslSpecialPaddingLiteral() { this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8] }
|
||||
OpenSslPaddingLiteral() { this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8] }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` has the given `type`.
|
||||
* Given a `KnownOpenSslPaddingAlgorithmExpr`, converts this to a padding family type.
|
||||
* Does not bind if there is no mapping (no mapping to 'unknown' or 'other').
|
||||
*/
|
||||
@@ -46,6 +45,9 @@ predicate knownOpenSslConstantToPaddingFamilyType(
|
||||
)
|
||||
}
|
||||
|
||||
//abstract class OpenSslPaddingAlgorithmInstance extends OpenSslAlgorithmInstance, Crypto::PaddingAlgorithmInstance{}
|
||||
// TODO: need to alter this to include known padding constants which don't have the
|
||||
// same mechanics as those with known nids
|
||||
class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::PaddingAlgorithmInstance instanceof Expr
|
||||
{
|
||||
@@ -64,8 +66,7 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) and
|
||||
isPaddingSpecificConsumer = false
|
||||
@@ -78,13 +79,12 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
isPaddingSpecificConsumer = false
|
||||
or
|
||||
// Possibility 3: padding-specific literal
|
||||
this instanceof OpenSslSpecialPaddingLiteral and
|
||||
this instanceof OpenSslPaddingLiteral and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a padding-specific consumer
|
||||
RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
) and
|
||||
@@ -124,6 +124,44 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
}
|
||||
}
|
||||
|
||||
// // Values used for EVP_PKEY_CTX_set_rsa_padding, these are
|
||||
// // not the same as 'typical' constants found in the set of known algorithm constants
|
||||
// // they do not have an NID
|
||||
// // TODO: what about setting the padding directly?
|
||||
// class KnownRSAPaddingConstant extends OpenSslPaddingAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof Literal
|
||||
// {
|
||||
// KnownRSAPaddingConstant() {
|
||||
// // from rsa.h in openssl:
|
||||
// // # define RSA_PKCS1_PADDING 1
|
||||
// // # define RSA_NO_PADDING 3
|
||||
// // # define RSA_PKCS1_OAEP_PADDING 4
|
||||
// // # define RSA_X931_PADDING 5
|
||||
// // /* EVP_PKEY_ only */
|
||||
// // # define RSA_PKCS1_PSS_PADDING 6
|
||||
// // # define RSA_PKCS1_WITH_TLS_PADDING 7
|
||||
// // /* internal RSA_ only */
|
||||
// // # define RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING 8
|
||||
// this instanceof Literal and
|
||||
// this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8]
|
||||
// // TODO: trace to padding-specific consumers
|
||||
// RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
|
||||
// }
|
||||
// override string getRawPaddingAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
// override Crypto::TPaddingType getPaddingType() {
|
||||
// if this.(Literal).getValue().toInt() in [1, 6, 7, 8]
|
||||
// then result = Crypto::PKCS1_v1_5()
|
||||
// else
|
||||
// if this.(Literal).getValue().toInt() = 3
|
||||
// then result = Crypto::NoPadding()
|
||||
// else
|
||||
// if this.(Literal).getValue().toInt() = 4
|
||||
// then result = Crypto::OAEP()
|
||||
// else
|
||||
// if this.(Literal).getValue().toInt() = 5
|
||||
// then result = Crypto::ANSI_X9_23()
|
||||
// else result = Crypto::OtherPadding()
|
||||
// }
|
||||
// }
|
||||
class OaepPaddingAlgorithmInstance extends Crypto::OaepPaddingAlgorithmInstance,
|
||||
KnownOpenSslPaddingConstantAlgorithmInstance
|
||||
{
|
||||
@@ -132,18 +170,10 @@ class OaepPaddingAlgorithmInstance extends Crypto::OaepPaddingAlgorithmInstance,
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getOaepEncodingHashAlgorithm() {
|
||||
exists(OperationStep s |
|
||||
this.getAvc().(AvcContextCreationStep).flowsToOperationStep(s) and
|
||||
s.getAlgorithmValueConsumerForInput(HashAlgorithmOaepIO()) =
|
||||
result.(OpenSslAlgorithmInstance).getAvc()
|
||||
)
|
||||
none() //TODO
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getMgf1HashAlgorithm() {
|
||||
exists(OperationStep s |
|
||||
this.getAvc().(AvcContextCreationStep).flowsToOperationStep(s) and
|
||||
s.getAlgorithmValueConsumerForInput(HashAlgorithmMgf1IO()) =
|
||||
result.(OpenSslAlgorithmInstance).getAvc()
|
||||
)
|
||||
none() //TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,7 @@ class KnownOpenSslSignatureConstantAlgorithmInstance extends OpenSslAlgorithmIns
|
||||
// Sink is an argument to a signature getter call
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
// NOTE: src literals can be ints or strings, so need to consider asExpr and asIndirectExpr
|
||||
this = [src.asExpr(), src.asIndirectExpr()] and
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
|
||||
@@ -12,17 +12,15 @@ class EvpCipherAlgorithmValueConsumer extends CipherAlgorithmValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpCipherAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() in ["EVP_get_cipherbyname", "EVP_get_cipherbyobj"] and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_get_cipherbynid" and
|
||||
// algorithm is an NID (int), use asExpr()
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_get_cipherbyname", "EVP_get_cipherbyobj", "EVP_get_cipherbynid"
|
||||
] and
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() in ["EVP_CIPHER_fetch", "EVP_ASYM_CIPHER_fetch"] and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class DirectAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer instanc
|
||||
*/
|
||||
override DataFlow::Node getResultNode() {
|
||||
this instanceof OpenSslDirectAlgorithmFetchCall and
|
||||
result.asIndirectExpr() = this
|
||||
result.asExpr() = this
|
||||
// NOTE: if instanceof OpenSslDirectAlgorithmOperationCall then there is no algorithm generated
|
||||
// the algorithm is directly used
|
||||
}
|
||||
|
||||
@@ -12,19 +12,14 @@ class EvpEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpEllipticCurveAlgorithmConsumer() {
|
||||
resultNode.asIndirectExpr() = this.(Call) and // in all cases the result is the return
|
||||
resultNode.asExpr() = this.(Call) and // in all cases the result is the return
|
||||
(
|
||||
this.(Call).getTarget().getName() = "EVP_EC_gen" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EC_KEY_new_by_curve_name" and
|
||||
// algorithm is an NID (int), use asExpr()
|
||||
this.(Call).getTarget().getName() in ["EVP_EC_gen", "EC_KEY_new_by_curve_name"] and
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EC_KEY_new_by_curve_name_ex", "EVP_PKEY_CTX_set_ec_paramgen_curve_nid"
|
||||
] and
|
||||
// algorithm is an NID (int), use asExpr
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ abstract class HashAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer
|
||||
/**
|
||||
* An EVP_Q_Digest directly consumes algorithm constant values
|
||||
*/
|
||||
class Evp_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer instanceof Call {
|
||||
Evp_Q_Digest_Algorithm_Consumer() { super.getTarget().getName() = "EVP_Q_digest" }
|
||||
class Evp_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer {
|
||||
Evp_Q_Digest_Algorithm_Consumer() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() {
|
||||
result.asIndirectExpr() = super.getArgument(1)
|
||||
result.asExpr() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
@@ -42,7 +42,7 @@ class EvpPkeySetCtxALgorithmConsumer extends HashAlgorithmValueConsumer {
|
||||
"EVP_PKEY_CTX_set_rsa_mgf1_md_name", "EVP_PKEY_CTX_set_rsa_oaep_md_name",
|
||||
"EVP_PKEY_CTX_set_dsa_paramgen_md_props"
|
||||
] and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
override DataFlow::Node getResultNode() { none() }
|
||||
@@ -64,18 +64,18 @@ class EvpDigestAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpDigestAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_get_digestbyname", "EVP_get_digestbynid", "EVP_get_digestbyobj"
|
||||
] and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(0)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_MD_fetch" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(2)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,21 +87,3 @@ class EvpDigestAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
|
||||
exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
|
||||
}
|
||||
}
|
||||
|
||||
class RsaSignOrVerifyHashAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
|
||||
DataFlow::Node valueArgNode;
|
||||
|
||||
RsaSignOrVerifyHashAlgorithmValueConsumer() {
|
||||
this.(Call).getTarget().getName() in ["RSA_sign", "RSA_verify"] and
|
||||
// arg 0 is an int, use asExpr
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getResultNode() { none() }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ class EvpKemAlgorithmValueConsumer extends KemAlgorithmValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpKemAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() = "EVP_KEM_fetch" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ class EvpKeyExchangeAlgorithmValueConsumer extends KeyExchangeAlgorithmValueCons
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpKeyExchangeAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() = "EVP_KEYEXCH_fetch" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class EvpPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpPKeyAlgorithmConsumer() {
|
||||
resultNode.asIndirectExpr() = this.(Call) and // in all cases the result is the return
|
||||
resultNode.asExpr() = this.(Call) and // in all cases the result is the return
|
||||
(
|
||||
// NOTE: some of these consumers are themselves key gen operations,
|
||||
// in these cases, the operation will be created separately for the same function.
|
||||
@@ -19,7 +19,6 @@ class EvpPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
"EVP_PKEY_CTX_new_id", "EVP_PKEY_new_raw_private_key", "EVP_PKEY_new_raw_public_key",
|
||||
"EVP_PKEY_new_mac_key"
|
||||
] and
|
||||
// Algorithm is an int, use asExpr
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() in [
|
||||
@@ -27,8 +26,7 @@ class EvpPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
"EVP_PKEY_new_raw_public_key_ex", "EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_ctrl_uint64",
|
||||
"EVP_PKEY_CTX_ctrl_str", "EVP_PKEY_CTX_set_group_name"
|
||||
] and
|
||||
// AAlgorithm is a char*, use asIndirectExpr
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
or
|
||||
// argInd 2 is 'type' which can be RSA, or EC
|
||||
// if RSA argInd 3 is the key size, else if EC argInd 3 is the curve name
|
||||
@@ -40,10 +38,10 @@ class EvpPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
// Elliptic curve case
|
||||
// If the argInd 3 is a derived type (pointer or array) then assume it is a curve name
|
||||
if this.(Call).getArgument(3).getType().getUnderlyingType() instanceof DerivedType
|
||||
then valueArgNode.asIndirectExpr() = this.(Call).getArgument(3)
|
||||
then valueArgNode.asExpr() = this.(Call).getArgument(3)
|
||||
else
|
||||
// All other cases
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(2)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,9 +14,8 @@ class Evp_PKey_Ctx_set_rsa_padding_AlgorithmValueConsumer extends PaddingAlgorit
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
Evp_PKey_Ctx_set_rsa_padding_AlgorithmValueConsumer() {
|
||||
resultNode.asDefiningArgument() = this.(Call).getArgument(0) and
|
||||
resultNode.asExpr() = this and
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_rsa_padding" and
|
||||
// algorithm is an int, use asExpr
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@ class EvpSignatureAlgorithmValueConsumer extends SignatureAlgorithmValueConsumer
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EvpSignatureAlgorithmValueConsumer() {
|
||||
resultNode.asIndirectExpr() = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
// EVP_SIGNATURE
|
||||
this.(Call).getTarget().getName() = "EVP_SIGNATURE_fetch" and
|
||||
valueArgNode.asIndirectExpr() = this.(Call).getArgument(1)
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
// EVP_PKEY_get1_DSA, EVP_PKEY_get1_RSA
|
||||
// DSA_SIG_new, DSA_SIG_get0 ?
|
||||
// DSA_SIG_new, DSA_SIG_get0, RSA_sign ?
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
private import experimental.quantum.Language
|
||||
|
||||
/**
|
||||
* A call to `BN_bn2bin`.
|
||||
* Commonly used to extract partial bytes from a signature,
|
||||
* e.g., a signature from DSA_do_sign, passed to DSA_do_verify
|
||||
* - int BN_bn2bin(const BIGNUM *a, unsigned char *to);
|
||||
*/
|
||||
class BnBn2BinCalStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
BnBn2BinCalStep() {
|
||||
call.getTarget().getName() = "BN_bn2bin" and
|
||||
call.getArgument(0) = this.asIndirectExpr()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() { result.asDefiningArgument() = call.getArgument(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `BN_bin2bn`.
|
||||
* Commonly used to convert to a signature for DSA_do_verify
|
||||
* - BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
|
||||
*/
|
||||
class BnBin2BnCallStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
BnBin2BnCallStep() {
|
||||
call.getTarget().getName() = "BN_bin2bn" and
|
||||
call.getArgument(0) = this.asIndirectExpr()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() { result.asDefiningArgument() = call.getArgument(2) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `RSA_set0_key` or `DSA_SIG_set0`.
|
||||
* Often used in combination with BN_bin2bn, to construct a signature.
|
||||
*/
|
||||
class RsaSet0KeyCallStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
RsaSet0KeyCallStep() {
|
||||
(call.getTarget().getName() = "RSA_set0_key" or call.getTarget().getName() = "DSA_SIG_set0") and
|
||||
this.asIndirectExpr() in [call.getArgument(1), call.getArgument(2), call.getArgument(3)]
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() { result.asDefiningArgument() = call.getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `d2i_DSA_SIG`. This is a pass through of a signature of one form to another.
|
||||
* - DSA_SIG *d2i_DSA_SIG(DSA_SIG **sig, const unsigned char **pp, long length);
|
||||
*/
|
||||
class D2iDsaSigCallStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
D2iDsaSigCallStep() {
|
||||
call.getTarget().getName() = "d2i_DSA_SIG" and
|
||||
this.asIndirectExpr() = call.getArgument(1)
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() {
|
||||
// If arg 0 specified, the same pointer is returned, if not specified
|
||||
// a new allocation is returned.
|
||||
result.asDefiningArgument() = call.getArgument(0) or
|
||||
result.asIndirectExpr() = call
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `DSA_SIG_get0`.
|
||||
* Converts a DSA_Sig into its components, which are commonly used with BN_bn2Bin to
|
||||
* construct a char* signature.
|
||||
* - void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
|
||||
*/
|
||||
class DsaSigGet0CallStep extends AdditionalFlowInputStep {
|
||||
Call call;
|
||||
|
||||
DsaSigGet0CallStep() {
|
||||
call.getTarget().getName() = "DSA_SIG_get0" and
|
||||
this.asIndirectExpr() = call.getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() {
|
||||
result.asDefiningArgument() = call.getArgument(1)
|
||||
or
|
||||
result.asDefiningArgument() = call.getArgument(2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_get1_RSA` or `EVP_PKEY_get1_DSA`
|
||||
* - RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
|
||||
* - DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey);
|
||||
* A key input is converted into a key output, a key is not generated.
|
||||
*/
|
||||
class EvpPkeyGet1RsaOrDsa extends AdditionalFlowInputStep {
|
||||
Call c;
|
||||
|
||||
EvpPkeyGet1RsaOrDsa() {
|
||||
c.getTarget().getName() = ["EVP_PKEY_get1_RSA", "EVP_PKEY_get1_DSA"] and
|
||||
this.asIndirectExpr() = c.getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput() { result.asIndirectExpr() = c }
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
/**
|
||||
@@ -13,9 +13,7 @@ module AvcToCallArgConfig implements DataFlow::ConfigSig {
|
||||
* Trace to any call accepting the algorithm.
|
||||
* NOTE: users must restrict this set to the operations they are interested in.
|
||||
*/
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(Call c | c.getAnArgument() = [sink.asIndirectExpr(), sink.asExpr()])
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { exists(Call c | c.getAnArgument() = sink.asExpr()) }
|
||||
}
|
||||
|
||||
module AvcToCallArgFlow = TaintTracking::Global<AvcToCallArgConfig>;
|
||||
module AvcToCallArgFlow = DataFlow::Global<AvcToCallArgConfig>;
|
||||
|
||||
@@ -4,5 +4,4 @@ module OpenSslModel {
|
||||
import Operations.OpenSSLOperations
|
||||
import Random
|
||||
import GenericSourceCandidateLiteral
|
||||
import ArtifactPassthrough
|
||||
}
|
||||
|
||||
@@ -3,48 +3,24 @@ private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import EVPPKeyCtxInitializer
|
||||
|
||||
/**
|
||||
* A base class for all final cipher operation steps.
|
||||
*/
|
||||
abstract class FinalCipherOperationStep extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base configuration for all EVP cipher operations.
|
||||
*/
|
||||
abstract class EvpCipherOperationFinalStep extends FinalCipherOperationStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for all EVP cipher operations.
|
||||
*/
|
||||
abstract class EvpCipherInitializer extends OperationStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
result.asExpr() = this.getArgument(1) and
|
||||
type = PrimaryAlgorithmIO() and
|
||||
// Constants that are not equal to zero or
|
||||
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
|
||||
// A zero (null) value typically indicates use of this operation step to initialize
|
||||
// other out parameters in a multi-step initialization.
|
||||
(
|
||||
exists(result.asIndirectExpr().getValue())
|
||||
implies
|
||||
result.asIndirectExpr().getValue().toInt() != 0
|
||||
)
|
||||
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -62,15 +38,11 @@ abstract class EvpEXInitializer extends EvpCipherInitializer {
|
||||
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
|
||||
// A zero (null) value typically indicates use of this operation step to initialize
|
||||
// other out parameters in a multi-step initialization.
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(3) and type = KeyIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(4) and type = IVorNonceIO()
|
||||
result.asExpr() = this.getArgument(4) and type = IVorNonceIO()
|
||||
) and
|
||||
(
|
||||
exists(result.asIndirectExpr().getValue())
|
||||
implies
|
||||
result.asIndirectExpr().getValue().toInt() != 0
|
||||
)
|
||||
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,9 +53,9 @@ abstract class EvpEX2Initializer extends EvpCipherInitializer {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(2) and type = KeyIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = IVorNonceIO()
|
||||
result.asExpr() = this.getArgument(3) and type = IVorNonceIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +90,6 @@ class Evp_Cipher_EX2_or_Simple_Init_Call extends EvpEX2Initializer {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
this.getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
// the key op subtype is an int, use asExpr
|
||||
result.asExpr() = this.getArgument(4) and
|
||||
type = KeyOperationSubtypeIO()
|
||||
}
|
||||
@@ -136,13 +107,13 @@ class EvpPkeyEncryptDecryptInit extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = OsslParamIO()
|
||||
result.asExpr() = this.getArgument(1) and type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -154,7 +125,6 @@ class EvpCipherInitSKeyCall extends EvpEX2Initializer {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
// the key op subtype is an int, use asExpr
|
||||
result.asExpr() = this.getArgument(5) and
|
||||
type = KeyOperationSubtypeIO()
|
||||
}
|
||||
@@ -171,20 +141,35 @@ class EvpCipherUpdateCall extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = CiphertextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base configuration for all EVP cipher operations.
|
||||
*/
|
||||
abstract class EvpCipherOperationFinalStep extends OperationStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to EVP_Cipher.
|
||||
*/
|
||||
@@ -194,13 +179,13 @@ class EvpCipherCall extends EvpCipherOperationFinalStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
super.getInput(type) = result
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(2) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
super.getOutput(type) = result
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = CiphertextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,50 +216,28 @@ class EvpCipherFinalCall extends EvpCipherOperationFinalStep {
|
||||
*/
|
||||
class EvpPKeyCipherOperation extends EvpCipherOperationFinalStep {
|
||||
EvpPKeyCipherOperation() {
|
||||
this.getTarget().getName() in ["EVP_PKEY_encrypt", "EVP_PKEY_decrypt"] and
|
||||
// TODO: for now ignore this operation entirely if it is setting the cipher text to null
|
||||
// this needs to be re-evalauted if this scenario sets other values worth tracking
|
||||
(
|
||||
exists(this.(Call).getArgument(1).getValue())
|
||||
implies
|
||||
this.(Call).getArgument(1).getValue().toInt() != 0
|
||||
)
|
||||
this.getTarget().getName() in ["EVP_PKEY_encrypt", "EVP_PKEY_decrypt"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
super.getInput(type) = result
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
super.getOutput(type) = result
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and
|
||||
type = CiphertextIO() and
|
||||
this.getStepType() = FinalStep()
|
||||
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
|
||||
// TODO: could indicate text lengths here, as well
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() {
|
||||
// When the output buffer is null, the step is not a final step
|
||||
// it is used to get the buffer size, if 0 consider it an initialization step
|
||||
// NOTE/TODO: not tracing 0 to the arg, just looking for 0 directly in param
|
||||
// the assumption is this is the common case, but we may want to make this more
|
||||
// robust and support a dataflow.
|
||||
result = FinalStep() and
|
||||
(exists(super.getArgument(1).getValue()) implies super.getArgument(1).getValue().toInt() != 0)
|
||||
or
|
||||
result = InitializerStep() and
|
||||
super.getArgument(1).getValue().toInt() = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An EVP cipher operation instance.
|
||||
* Any operation step that is a final operation step for EVP cipher operation steps.
|
||||
*/
|
||||
class OpenSslCipherOperationInstance extends Crypto::KeyOperationInstance instanceof FinalCipherOperationStep
|
||||
class EvpCipherOperationInstance extends Crypto::KeyOperationInstance instanceof EvpCipherOperationFinalStep
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
/**
|
||||
* Initializers for EVP PKey
|
||||
* These are used to create a Pkey context or set properties on a Pkey context
|
||||
* e.g., key size, hash algorithms, curves, padding schemes, etc.
|
||||
* Meant to capture more general purpose initializers that aren't necessarily
|
||||
* tied to a specific operation. If tied to an operation (i.e., in the docs)
|
||||
* we recommend defining defining all together in the same operation definition qll.
|
||||
* including:
|
||||
* https://docs.openssl.org/3.0/man3/EVP_PKEY_CTX_ctrl/
|
||||
* https://docs.openssl.org/3.0/man3/EVP_EncryptInit/#synopsis
|
||||
@@ -31,16 +26,14 @@ class EvpNewKeyCtx extends OperationStep instanceof Call {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = keyArg and type = KeyIO()
|
||||
result.asExpr() = keyArg and type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
|
||||
result.asIndirectExpr() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = OsslLibContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asIndirectExpr() = this and type = ContextIO()
|
||||
}
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = ContextIO() }
|
||||
|
||||
override OperationStepType getStepType() { result = ContextCreationStep() }
|
||||
}
|
||||
@@ -54,13 +47,13 @@ class EvpCtxSetEcParamgenCurveNidInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -78,46 +71,23 @@ class EvpCtxSetEcParamgenCurveNidInitializer extends OperationStep {
|
||||
* - `EVP_PKEY_CTX_set_ecdh_kdf_md`
|
||||
*/
|
||||
class EvpCtxSetHashInitializer extends OperationStep {
|
||||
boolean isOaep;
|
||||
boolean isMgf1;
|
||||
|
||||
EvpCtxSetHashInitializer() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_signature_md", "EVP_PKEY_CTX_set_dsa_paramgen_md",
|
||||
"EVP_PKEY_CTX_set_signature_md", "EVP_PKEY_CTX_set_rsa_mgf1_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_mgf1_md", "EVP_PKEY_CTX_set_rsa_oaep_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_oaep_md", "EVP_PKEY_CTX_set_dsa_paramgen_md",
|
||||
"EVP_PKEY_CTX_set_dh_kdf_md", "EVP_PKEY_CTX_set_ecdh_kdf_md"
|
||||
] and
|
||||
isOaep = false and
|
||||
isMgf1 = false
|
||||
or
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_rsa_mgf1_md_name", "EVP_PKEY_CTX_set_rsa_mgf1_md"
|
||||
] and
|
||||
isOaep = false and
|
||||
isMgf1 = true
|
||||
or
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_rsa_oaep_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_oaep_md"
|
||||
] and
|
||||
isOaep = true and
|
||||
isMgf1 = false
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
type = HashAlgorithmIO() and
|
||||
isOaep = false and
|
||||
isMgf1 = false
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmOaepIO() and isOaep = true
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmMgf1IO() and isMgf1 = true
|
||||
result.asExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -136,13 +106,13 @@ class EvpCtxSetKeySizeInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = KeySizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -152,16 +122,16 @@ class EvpCtxSetMacKeyInitializer extends OperationStep {
|
||||
EvpCtxSetMacKeyInitializer() { this.getTarget().getName() = "EVP_PKEY_CTX_set_mac_key" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = KeySizeIO()
|
||||
or
|
||||
// the raw key that is configured into the output key
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(1) and type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -173,14 +143,13 @@ class EvpCtxSetPaddingInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// The algorithm is an int: use asExpr
|
||||
result.asExpr() = this.getArgument(1) and type = PaddingAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -192,13 +161,13 @@ class EvpCtxSetSaltLengthInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = SaltLengthIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
|
||||
@@ -6,13 +6,6 @@ private import experimental.quantum.Language
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
/**
|
||||
* A base class for final digest operations.
|
||||
*/
|
||||
abstract class FinalDigestOperation extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to and EVP digest initializer, such as:
|
||||
* - `EVP_DigestInit`
|
||||
@@ -25,13 +18,13 @@ class EvpDigestInitVariantCalls extends OperationStep instanceof Call {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
}
|
||||
|
||||
@@ -45,49 +38,56 @@ class EvpDigestUpdateCall extends OperationStep instanceof Call {
|
||||
EvpDigestUpdateCall() { this.getTarget().getName() = "EVP_DigestUpdate" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for final digest operations.
|
||||
*/
|
||||
abstract class EvpFinalDigestOperationStep extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_Q_digest`
|
||||
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
*/
|
||||
class EvpQDigestOperation extends FinalDigestOperation instanceof Call {
|
||||
class EvpQDigestOperation extends EvpFinalDigestOperationStep instanceof Call {
|
||||
EvpQDigestOperation() { this.getTarget().getName() = "EVP_Q_digest" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(5) and type = DigestIO()
|
||||
}
|
||||
}
|
||||
|
||||
class EvpDigestOperation extends FinalDigestOperation instanceof Call {
|
||||
class EvpDigestOperation extends EvpFinalDigestOperationStep instanceof Call {
|
||||
EvpDigestOperation() { this.getTarget().getName() = "EVP_Digest" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(4) and type = PrimaryAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(4) and type = PrimaryAlgorithmIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
@@ -98,28 +98,27 @@ class EvpDigestOperation extends FinalDigestOperation instanceof Call {
|
||||
/**
|
||||
* A call to EVP_DigestFinal variants
|
||||
*/
|
||||
class EvpDigestFinalCall extends FinalDigestOperation instanceof Call {
|
||||
class EvpDigestFinalCall extends EvpFinalDigestOperationStep instanceof Call {
|
||||
EvpDigestFinalCall() {
|
||||
this.getTarget().getName() in ["EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = DigestIO()
|
||||
//result.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = this.getArgument(1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An openssl digest final hash operation instance
|
||||
*/
|
||||
class OpenSslDigestFinalOperationInstance extends Crypto::HashOperationInstance instanceof FinalDigestOperation
|
||||
class EvpDigestFinalOperationInstance extends Crypto::HashOperationInstance instanceof EvpFinalDigestOperationStep
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
|
||||
@@ -13,12 +13,10 @@ class ECKeyGen extends OperationStep instanceof Call {
|
||||
ECKeyGen() { this.(Call).getTarget().getName() = "EC_KEY_generate_key" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.(Call).getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.(Call).getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this and type = KeyIO()
|
||||
}
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
|
||||
|
||||
override OperationStepType getStepType() { result = ContextCreationStep() }
|
||||
}
|
||||
@@ -35,19 +33,16 @@ class EvpKeyGenInitialize extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for final key generation operation steps.
|
||||
*/
|
||||
abstract class KeyGenFinalOperationStep extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
@@ -59,26 +54,26 @@ class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
EvpPKeyQKeyGen() { this.getTarget().getName() = "EVP_PKEY_Q_keygen" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this and type = KeyIO()
|
||||
result.asExpr() = this and type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// When arg 3 is a derived type, it is a curve name, otherwise it is a key size for RSA if provided
|
||||
// and arg 2 is the algorithm type
|
||||
this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
result.asExpr() = this.getArgument(3) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
|
||||
result.asIndirectExpr() = this.getArgument(2) and
|
||||
result.asExpr() = this.getArgument(2) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
result.asExpr() = this.getArgument(3) and
|
||||
type = KeySizeIO()
|
||||
}
|
||||
}
|
||||
@@ -89,9 +84,7 @@ class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
class EvpRsaGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
EvpRsaGen() { this.getTarget().getName() = "EVP_RSA_gen" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this and type = KeyIO()
|
||||
}
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
|
||||
@@ -104,9 +97,7 @@ class EvpRsaGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
class RsaGenerateKey extends KeyGenFinalOperationStep instanceof Call {
|
||||
RsaGenerateKey() { this.getTarget().getName() = "RSA_generate_key" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this and type = KeyIO()
|
||||
}
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
|
||||
@@ -126,7 +117,7 @@ class RsaGenerateKeyEx extends KeyGenFinalOperationStep instanceof Call {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
// arg 0 comes in as a blank RSA key, which we consider a context,
|
||||
// on output it is considered a key
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,13 +128,13 @@ class EvpPkeyGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
EvpPkeyGen() { this.getTarget().getName() in ["EVP_PKEY_generate", "EVP_PKEY_keygen"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = KeyIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,14 +146,18 @@ class EvpNewMacKey extends KeyGenFinalOperationStep {
|
||||
EvpNewMacKey() { this.getTarget().getName() = "EVP_PKEY_new_mac_key" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// the raw key that is configured into the output key
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(2) and type = KeyIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(3) and type = KeySizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asIndirectExpr() = this and type = KeyIO()
|
||||
result.asExpr() = this and type = KeyIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +165,7 @@ class EvpNewMacKey extends KeyGenFinalOperationStep {
|
||||
/**
|
||||
* An `KeyGenerationOperationInstance` for the for all key gen final operation steps.
|
||||
*/
|
||||
class OpenSslKeyGenOperationInstance extends Crypto::KeyGenerationOperationInstance instanceof KeyGenFinalOperationStep
|
||||
class KeyGenOperationInstance extends Crypto::KeyGenerationOperationInstance instanceof KeyGenFinalOperationStep
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
// Importing these intializers here to ensure the are part of any model that is
|
||||
// using OpenSslOperationBase. This further ensures that initializers are tied to opeartions
|
||||
// even if only importing the operation by itself.
|
||||
@@ -58,11 +58,7 @@ newtype TIOType =
|
||||
// For OSSL_PARAM and OSSL_LIB_CTX use of OsslParamIO and OsslLibContextIO
|
||||
ContextIO() or
|
||||
DigestIO() or
|
||||
// For OAEP and MGF1 hashes, there is a special IO type for these hashes
|
||||
// it is recommended to set the most explicit type known, not both
|
||||
HashAlgorithmIO() or
|
||||
HashAlgorithmOaepIO() or
|
||||
HashAlgorithmMgf1IO() or
|
||||
IVorNonceIO() or
|
||||
KeyIO() or
|
||||
KeyOperationSubtypeIO() or
|
||||
@@ -75,13 +71,11 @@ newtype TIOType =
|
||||
PaddingAlgorithmIO() or
|
||||
// Plaintext also includes a message for digest, signature, verification, and mac generation
|
||||
PlaintextIO() or
|
||||
PlaintextSizeIO() or
|
||||
PrimaryAlgorithmIO() or
|
||||
RandomSourceIO() or
|
||||
SaltLengthIO() or
|
||||
SeedIO() or
|
||||
SignatureIO() or
|
||||
SignatureSizeIO()
|
||||
SignatureIO()
|
||||
|
||||
private string ioTypeToString(TIOType t) {
|
||||
t = CiphertextIO() and result = "CiphertextIO"
|
||||
@@ -110,8 +104,6 @@ private string ioTypeToString(TIOType t) {
|
||||
or
|
||||
t = PlaintextIO() and result = "PlaintextIO"
|
||||
or
|
||||
t = PlaintextSizeIO() and result = "PlaintextSizeIO"
|
||||
or
|
||||
t = PrimaryAlgorithmIO() and result = "PrimaryAlgorithmIO"
|
||||
or
|
||||
t = RandomSourceIO() and result = "RandomSourceIO"
|
||||
@@ -121,8 +113,6 @@ private string ioTypeToString(TIOType t) {
|
||||
t = SeedIO() and result = "SeedIO"
|
||||
or
|
||||
t = SignatureIO() and result = "SignatureIO"
|
||||
or
|
||||
t = SignatureSizeIO() and result = "SignatureSizeIO"
|
||||
}
|
||||
|
||||
class IOType extends TIOType {
|
||||
@@ -133,13 +123,13 @@ class IOType extends TIOType {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: add more initializers as needed
|
||||
/**
|
||||
* The type of step in an `OperationStep`.
|
||||
* - `ContextCreationStep`: the creation of a context from an algorithm or key.
|
||||
* for example `EVP_MD_CTX_create(EVP_sha256())` or `EVP_PKEY_CTX_new(pkey, NULL)`
|
||||
* - `InitializerStep`: the initialization of an operation or state through some sort of shared/accumulated context
|
||||
* for example `EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)`, may also be used for pass through
|
||||
* configuration, for example `EVP_PKEY_get1_RSA(key)` where a pkey is input into an RSA key return.
|
||||
* - `InitializerStep`: the initialization of an operation through some sort of shared/accumulated context
|
||||
* for example `EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)`
|
||||
* - `UpdateStep`: any operation that has and update/final paradigm, the update represents an intermediate step in an operation,
|
||||
* such as `EVP_DigestUpdate(ctx, data, len)`
|
||||
* - `FinalStep`: an ultimate operation step. This may be an explicit 'final' in an update/final paradigm, but not necessarily.
|
||||
@@ -199,7 +189,7 @@ abstract class OperationStep extends Call {
|
||||
*/
|
||||
predicate flowsToOperationStep(OperationStep sink) {
|
||||
sink = this or
|
||||
OperationStepCtxFlow::flow(this.getAnOutput(), [sink.getAnInput(), sink.getAnOutput()])
|
||||
OperationStepFlow::flow(this.getAnOutput(), sink.getAnInput())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +198,7 @@ abstract class OperationStep extends Call {
|
||||
*/
|
||||
predicate flowsFromOperationStep(OperationStep source) {
|
||||
source = this or
|
||||
OperationStepCtxFlow::flow(source.getAnOutput(), [this.getAnInput(), this.getAnOutput()])
|
||||
OperationStepFlow::flow(source.getAnOutput(), this.getAnInput())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,13 +220,10 @@ abstract class OperationStep extends Call {
|
||||
result.setsValue(type) and
|
||||
(
|
||||
// Do not consider a 'reset' to occur on updates
|
||||
// but only for resets that are part of the same update/finalize
|
||||
// progression (e.g., an update for an unrelated finalize is ignored)
|
||||
result.getStepType() = UpdateStep()
|
||||
or
|
||||
not exists(OperationStep reset |
|
||||
result != reset and
|
||||
result != this and
|
||||
reset.setsValue(type) and
|
||||
reset.flowsToOperationStep(this) and
|
||||
result.flowsToOperationStep(reset)
|
||||
@@ -258,11 +245,8 @@ abstract class OperationStep extends Call {
|
||||
|
||||
/**
|
||||
* Gets an AVC for the primary algorithm for this operation.
|
||||
* A primary algorithm is an AVC that either:
|
||||
* 0) `this` is an AVC (consider direct algorithm consumers like RSA_sign (algorithm is implicit) or EVP_PKEY_new_mac_key (NID is first arg) )
|
||||
* 1) flows to a ctx input directly or
|
||||
* 2) flows to a primary algorithm input directly or
|
||||
* 3) flows to a key input directly (algorithm held in a key will be considered primary)
|
||||
* A primary algorithm is an AVC that flows to a ctx input directly or
|
||||
* an AVC that flows to a primary algorithm input directly.
|
||||
* See `AvcContextCreationStep` for details about resetting scenarios.
|
||||
* Gets the first OperationStep an AVC flows to. If a context input,
|
||||
* the AVC is considered primary.
|
||||
@@ -270,24 +254,19 @@ abstract class OperationStep extends Call {
|
||||
* operation step (dominating operation step, see `getDominatingInitializersToStep`).
|
||||
*/
|
||||
Crypto::AlgorithmValueConsumer getPrimaryAlgorithmValueConsumer() {
|
||||
this instanceof Crypto::AlgorithmValueConsumer and result = this
|
||||
or
|
||||
exists(
|
||||
DataFlow::Node src, DataFlow::Node sink, IOType srcIntype, OperationStep avcConsumingPred
|
||||
|
|
||||
(srcIntype = ContextIO() or srcIntype = PrimaryAlgorithmIO() or srcIntype = KeyIO()) and
|
||||
avcConsumingPred.flowsToOperationStep(this) and
|
||||
src.asIndirectExpr() = result and
|
||||
sink = avcConsumingPred.getInput(srcIntype) and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink, IOType t, OperationStep avcSucc |
|
||||
(t = PrimaryAlgorithmIO() or t = ContextIO()) and
|
||||
avcSucc.flowsToOperationStep(this) and
|
||||
src.asExpr() = result and
|
||||
sink = avcSucc.getInput(t) and
|
||||
AvcToOperationStepFlow::flow(src, sink) and
|
||||
(
|
||||
// Case 1: the avcConsumingPred step is a dominating primary algorithm initialization step
|
||||
// or dominating key initialization step
|
||||
(srcIntype = PrimaryAlgorithmIO() or srcIntype = KeyIO()) and
|
||||
avcConsumingPred = this.getDominatingInitializersToStep(srcIntype)
|
||||
// Case 1: the avcSucc step is a dominating initialization step
|
||||
t = PrimaryAlgorithmIO() and
|
||||
avcSucc = this.getDominatingInitializersToStep(PrimaryAlgorithmIO())
|
||||
or
|
||||
// Case 2: the pred is a context input
|
||||
srcIntype = ContextIO()
|
||||
// Case 2: the succ is a context input (any avcSucc is valid)
|
||||
t = ContextIO()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -298,11 +277,9 @@ abstract class OperationStep extends Call {
|
||||
* TODO: generalize to use this for `getPrimaryAlgorithmValueConsumer`
|
||||
*/
|
||||
Crypto::AlgorithmValueConsumer getAlgorithmValueConsumerForInput(IOType type) {
|
||||
result = this and this.setsValue(type)
|
||||
or
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
AvcToOperationStepFlow::flow(src, sink) and
|
||||
src.asIndirectExpr() = result and
|
||||
src.asExpr() = result and
|
||||
sink = this.getInput(type)
|
||||
)
|
||||
}
|
||||
@@ -380,7 +357,7 @@ private class CtxCopyOutArgCall extends CtxPassThroughCall {
|
||||
|
||||
CtxCopyOutArgCall() {
|
||||
this.getTarget().getName().toLowerCase().matches("%copy%") and
|
||||
n1.asIndirectExpr() = this.getAnArgument() and
|
||||
n1.asExpr() = this.getAnArgument() and
|
||||
n1.getType() instanceof CtxType and
|
||||
n2.asDefiningArgument() = this.getAnArgument() and
|
||||
n2.getType() instanceof CtxType and
|
||||
@@ -401,18 +378,16 @@ private class CtxCopyReturnCall extends CtxPassThroughCall, CtxPointerExpr {
|
||||
|
||||
CtxCopyReturnCall() {
|
||||
this.getTarget().getName().toLowerCase().matches("%dup%") and
|
||||
n1.asIndirectExpr() = this.getAnArgument() and
|
||||
n1.asExpr() = this.getAnArgument() and
|
||||
n1.getType() instanceof CtxType
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result.asIndirectExpr() = this }
|
||||
override DataFlow::Node getNode2() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
// TODO: is this still needed? It appears to be (tests fail without it) but
|
||||
// I don't know why as EVP_PKEY_paramgen is an operation step and we pass through
|
||||
// operation steps already.
|
||||
// TODO: is this still needed?
|
||||
/**
|
||||
* A call to `EVP_PKEY_paramgen` acts as a kind of pass through.
|
||||
* It's output pkey is eventually used in a new operation generating
|
||||
@@ -426,10 +401,34 @@ private class CtxParamGenCall extends CtxPassThroughCall {
|
||||
|
||||
CtxParamGenCall() {
|
||||
this.getTarget().getName() = "EVP_PKEY_paramgen" and
|
||||
//Arg 0 is *ctx
|
||||
n1.asIndirectExpr() = this.getArgument(0) and
|
||||
//Arg 1 is **pkey
|
||||
n2.asDefiningArgument() = this.getArgument(1)
|
||||
n1.asExpr() = this.getArgument(0) and
|
||||
(
|
||||
n2.asExpr() = this.getArgument(1)
|
||||
or
|
||||
n2.asDefiningArgument() = this.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result = n2 }
|
||||
}
|
||||
|
||||
//TODO: I am not sure CallArgToCtxRet is needed anymore
|
||||
/**
|
||||
* If the current node is an argument to a function
|
||||
* that returns a pointer type, immediately flow through.
|
||||
* NOTE: this passthrough is required if we allow
|
||||
* intermediate steps to go into variables that are not a CTX type.
|
||||
* See for example `CtxParamGenCall`.
|
||||
*/
|
||||
private class CallArgToCtxRet extends CtxPassThroughCall, CtxPointerExpr {
|
||||
DataFlow::Node n1;
|
||||
DataFlow::Node n2;
|
||||
|
||||
CallArgToCtxRet() {
|
||||
this.getAnArgument() = n1.asExpr() and
|
||||
n2.asExpr() = this
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
@@ -440,7 +439,7 @@ private class CtxParamGenCall extends CtxPassThroughCall {
|
||||
/**
|
||||
* A flow configuration from any non-final `OperationStep` to any other `OperationStep`.
|
||||
*/
|
||||
module OperationStepCtxFlowConfig implements DataFlow::ConfigSig {
|
||||
module OperationStepFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(OperationStep s |
|
||||
s.getAnOutput() = source or
|
||||
@@ -456,39 +455,22 @@ module OperationStepCtxFlowConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(CtxClearCall c | c.getAnArgument() = [node.asExpr(), node.asIndirectExpr()])
|
||||
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
or
|
||||
exists(CtxPassThroughCall c | c.getNode1() = node1 and c.getNode2() = node2)
|
||||
or
|
||||
// Flow only through context and key inputs and outputs
|
||||
// keys and context generally hold unifying context that link multiple steps
|
||||
// Flow only out of finalize operations through key outputs, otherwise stop at final operations
|
||||
exists(OperationStep s, IOType inType, IOType outType |
|
||||
(s.getStepType() = FinalStep() implies outType = KeyIO()) and
|
||||
(
|
||||
inType = ContextIO()
|
||||
or
|
||||
inType = KeyIO()
|
||||
) and
|
||||
(
|
||||
outType = ContextIO()
|
||||
or
|
||||
outType = KeyIO()
|
||||
) and
|
||||
s.getInput(inType) = node1 and
|
||||
s.getOutput(outType) = node2
|
||||
)
|
||||
// Flow out through all outputs from an operation step if more than one output
|
||||
// is defined.
|
||||
exists(OperationStep s | s.getAnInput() = node1 and s.getAnOutput() = node2)
|
||||
// TODO: consideration for additional alises defined as follows:
|
||||
// if an output from an operation step itself flows from the output of another operation step
|
||||
// then the source of that flow's outputs (all of them) are potential aliases
|
||||
}
|
||||
}
|
||||
|
||||
module OperationStepCtxFlow = TaintTracking::Global<OperationStepCtxFlowConfig>;
|
||||
module OperationStepFlow = DataFlow::Global<OperationStepFlowConfig>;
|
||||
|
||||
/**
|
||||
* A flow from AVC to the first `OperationStep` the AVC reaches as an input.
|
||||
@@ -501,7 +483,7 @@ module AvcToOperationStepFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { exists(OperationStep s | s.getAnInput() = sink) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(CtxClearCall c | c.getAnArgument() = [node.asExpr(), node.asIndirectExpr()])
|
||||
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,7 +496,7 @@ module AvcToOperationStepFlowConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
}
|
||||
|
||||
module AvcToOperationStepFlow = TaintTracking::Global<AvcToOperationStepFlowConfig>;
|
||||
module AvcToOperationStepFlow = DataFlow::Global<AvcToOperationStepFlowConfig>;
|
||||
|
||||
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
|
||||
@@ -524,7 +506,7 @@ module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
}
|
||||
|
||||
module EncValToInitEncArgFlow = TaintTracking::Global<EncValToInitEncArgConfig>;
|
||||
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
|
||||
|
||||
private Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
|
||||
i = 0 and
|
||||
|
||||
@@ -6,25 +6,12 @@ private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AvcFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
|
||||
// TODO: verification functions
|
||||
/**
|
||||
* A base class for final signature operations.
|
||||
* The operation must be known to always be a signature operation,
|
||||
* and not a MAC operation. Used for both verification and signing.
|
||||
* NOTE: even an operation that may be a mac or signature but is known to take in
|
||||
* only signature configurations should extend `SignatureOrMacFinalOperation`.
|
||||
*/
|
||||
abstract class SignatureFinalOperation extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for final signature or MAC operations.
|
||||
* The operation must be known to always be a signature or MAC operation.
|
||||
* Used for both verification or signing.
|
||||
*/
|
||||
abstract class SignatureOrMacFinalOperation extends OperationStep {
|
||||
abstract class EvpSignatureFinalOperation extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
@@ -37,32 +24,36 @@ class EvpSignatureDigestInitializer extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
result.asExpr() = this.getArgument(3) and
|
||||
type = OsslLibContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = HashAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(2) and type = HashAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit" and
|
||||
result.asIndirectExpr() = this.getArgument(4) and
|
||||
result.asExpr() = this.getArgument(4) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(5) and
|
||||
result.asExpr() = this.getArgument(5) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(6) and
|
||||
result.asExpr() = this.getArgument(6) and
|
||||
type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// EVP_PKEY_CTX
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asExpr() = this.getArgument(6) and
|
||||
type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -75,13 +66,13 @@ class EvpSignInit extends OperationStep {
|
||||
EvpSignInit() { this.getTarget().getName() in ["EVP_SignInit", "EVP_SignInit_ex"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
result.asExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -103,22 +94,22 @@ class EvpPkeySignInit extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
result.asExpr() = this.getArgument(1) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_PKEY_sign_init_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
result.asExpr() = this.getArgument(1) and
|
||||
type = OsslParamIO()
|
||||
or
|
||||
// Argument 2 (0 based) only exists for EVP_PKEY_sign_init_ex2 and EVP_PKEY_sign_message_init
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = OsslParamIO()
|
||||
result.asExpr() = this.getArgument(2) and type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
@@ -135,13 +126,13 @@ class EvpSignatureUpdateCall extends OperationStep {
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
@@ -150,496 +141,73 @@ class EvpSignatureUpdateCall extends OperationStep {
|
||||
/**
|
||||
* A call to EVP_SignFinal or EVP_SignFinal_ex.
|
||||
*/
|
||||
class EvpSignFinal extends SignatureFinalOperation {
|
||||
class EvpSignFinal extends EvpSignatureFinalOperation {
|
||||
EvpSignFinal() { this.getTarget().getName() in ["EVP_SignFinal_ex", "EVP_SignFinal"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = KeyIO()
|
||||
result.asExpr() = this.getArgument(3) and type = KeyIO()
|
||||
or
|
||||
// params above 3 (0-based) only exist for EVP_SignFinal_ex
|
||||
result.asIndirectExpr() = this.getArgument(4) and
|
||||
result.asExpr() = this.getArgument(4) and
|
||||
type = OsslLibContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
result.asExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_PKEY_sign.
|
||||
* A call to EVP_DigestSign or EVP_PKEY_sign.
|
||||
*/
|
||||
class EvpPkeySign extends SignatureFinalOperation {
|
||||
EvpPkeySign() {
|
||||
this.getTarget().getName() = "EVP_PKEY_sign" and
|
||||
// Setting signature to NULL is not a final sign step but an
|
||||
// intermediary step used to get the required buffer size.
|
||||
// not tracking these calls.
|
||||
(
|
||||
exists(this.(Call).getArgument(1).getValue())
|
||||
implies
|
||||
this.(Call).getArgument(1).getValue().toInt() != 0
|
||||
)
|
||||
}
|
||||
class EvpDigestSign extends EvpSignatureFinalOperation {
|
||||
EvpDigestSign() { this.getTarget().getName() in ["EVP_DigestSign", "EVP_PKEY_sign"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
result.asExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestSign.
|
||||
* This is a mac or sign operation.
|
||||
* A call to EVP_DigestSignFinal or EVP_PKEY_sign_message_final.
|
||||
*/
|
||||
class EvpDigestSign extends SignatureOrMacFinalOperation {
|
||||
EvpDigestSign() { this.getTarget().getName() = "EVP_DigestSign" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_PKEY_sign_message_final.
|
||||
*/
|
||||
class EvpPkeySignFinal extends SignatureFinalOperation {
|
||||
EvpPkeySignFinal() {
|
||||
this.getTarget().getName() = "EVP_PKEY_sign_message_final" and
|
||||
// Setting signature to NULL is not a final sign step but an
|
||||
// intermediary step used to get the required buffer size.
|
||||
// not tracking these calls.
|
||||
(
|
||||
exists(this.(Call).getArgument(1).getValue())
|
||||
implies
|
||||
this.(Call).getArgument(1).getValue().toInt() != 0
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestSignFinal.
|
||||
* This is a mac or sign operation.
|
||||
*/
|
||||
class EvpDigestSignFinal extends SignatureOrMacFinalOperation {
|
||||
EvpDigestSignFinal() {
|
||||
this.getTarget().getName() = "EVP_DigestSignFinal" and
|
||||
// Setting signature to NULL is not a final sign step but an
|
||||
// intermediary step used to get the required buffer size.
|
||||
// not tracking these calls.
|
||||
(
|
||||
exists(this.(Call).getArgument(1).getValue())
|
||||
implies
|
||||
this.(Call).getArgument(1).getValue().toInt() != 0
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestVerifyInit or EVP_DigestVerifyInit_ex.
|
||||
*/
|
||||
class EvpDigestVerifyInit extends OperationStep {
|
||||
EvpDigestVerifyInit() {
|
||||
this.getTarget().getName() in ["EVP_DigestVerifyInit", "EVP_DigestVerifyInit_ex"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = HashAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestVerifyInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
type = OsslLibContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestVerifyInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(5) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestVerifyInit" and
|
||||
result.asIndirectExpr() = this.getArgument(4) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestVerifyInit_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(6) and
|
||||
type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestVerifyUpdate.
|
||||
*/
|
||||
class EvpDigestVerifyUpdate extends OperationStep {
|
||||
EvpDigestVerifyUpdate() { this.getTarget().getName() = "EVP_DigestVerifyUpdate" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestVerifyFinal
|
||||
*/
|
||||
class EvpDigestVerifyFinal extends SignatureFinalOperation {
|
||||
EvpDigestVerifyFinal() { this.getTarget().getName() = "EVP_DigestVerifyFinal" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestVerify
|
||||
*/
|
||||
class EvpDigestVerify extends SignatureFinalOperation {
|
||||
EvpDigestVerify() { this.getTarget().getName() = "EVP_DigestVerify" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_verify_init`, `EVP_PKEY_verify_init_ex`,
|
||||
* `EVP_PKEY_verify_init_ex2`, or `EVP_PKEY_verify_message_init`
|
||||
* https://docs.openssl.org/master/man3/EVP_PKEY_verify/#synopsis
|
||||
*/
|
||||
class EvpVerifyInit extends OperationStep {
|
||||
EvpVerifyInit() {
|
||||
class EvpDigestAndPkeySignFinal extends EvpSignatureFinalOperation {
|
||||
EvpDigestAndPkeySignFinal() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_verify_init", "EVP_PKEY_verify_init_ex", "EVP_PKEY_verify_init_ex2",
|
||||
"EVP_PKEY_verify_message_init"
|
||||
"EVP_DigestSignFinal",
|
||||
"EVP_PKEY_sign_message_final"
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_PKEY_verify_init_ex" and
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
type = OsslParamIO()
|
||||
or
|
||||
this.getTarget().getName() in ["EVP_PKEY_verify_init_ex2", "EVP_PKEY_verify_message_init"] and
|
||||
result.asIndirectExpr() = this.getArgument(1) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() in ["EVP_PKEY_verify_init_ex2", "EVP_PKEY_verify_message_init"] and
|
||||
result.asIndirectExpr() = this.getArgument(2) and
|
||||
type = OsslParamIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_CTX_set_signature`
|
||||
* https://docs.openssl.org/master/man3/EVP_PKEY_verify/
|
||||
*/
|
||||
class EvpCtxSetSignatureInitializer extends OperationStep {
|
||||
EvpCtxSetSignatureInitializer() { this.getTarget().getName() = "EVP_PKEY_CTX_set_signature" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_verify_message_update`.
|
||||
*/
|
||||
class EvpVerifyMessageUpdate extends OperationStep {
|
||||
EvpVerifyMessageUpdate() { this.getTarget().getName() = "EVP_PKEY_verify_message_update" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = PlaintextSizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_verify_message_final`.
|
||||
*/
|
||||
class EvpVerifyMessageFinal extends SignatureFinalOperation {
|
||||
EvpVerifyMessageFinal() { this.getTarget().getName() = "EVP_PKEY_verify_message_final" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_verify`
|
||||
*/
|
||||
class EvpVerify extends SignatureFinalOperation {
|
||||
EvpVerify() { this.getTarget().getName() = "EVP_PKEY_verify" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(4) and type = PlaintextSizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `RSA_sign` or `RSA_verify`.
|
||||
* https://docs.openssl.org/3.0/man3/RSA_sign/
|
||||
*/
|
||||
class RsaSignorVerify extends SignatureFinalOperation {
|
||||
RsaSignorVerify() { this.getTarget().getName() in ["RSA_sign", "RSA_verify"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
// Arg 0 is an NID (so asExpr not asIndirectExpr)
|
||||
result.asExpr() = this.getArgument(0) and type = HashAlgorithmIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = PlaintextSizeIO()
|
||||
or
|
||||
this.getTarget().getName() = "RSA_verify" and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
type = SignatureIO()
|
||||
or
|
||||
this.getTarget().getName() = "RSA_verify" and
|
||||
result.asIndirectExpr() = this.getArgument(4) and
|
||||
type = SignatureSizeIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(5) and type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "RSA_sign" and
|
||||
result.asDefiningArgument() = this.getArgument(3) and
|
||||
type = SignatureIO()
|
||||
or
|
||||
this.getTarget().getName() = "RSA_sign" and
|
||||
type = SignatureSizeIO() and
|
||||
result.asDefiningArgument() = this.getArgument(4)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `DSA_do_sign` or `DSA_do_verify`
|
||||
*/
|
||||
class DsaDoSignOrVerify extends SignatureFinalOperation {
|
||||
DsaDoSignOrVerify() { this.getTarget().getName() in ["DSA_do_sign", "DSA_do_verify"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = PlaintextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = PlaintextSizeIO()
|
||||
or
|
||||
this.getTarget().getName() = "DSA_do_sign" and
|
||||
result.asIndirectExpr() = this.getArgument(2) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "DSA_do_verify" and
|
||||
result.asIndirectExpr() = this.getArgument(2) and
|
||||
type = SignatureIO()
|
||||
or
|
||||
this.getTarget().getName() = "DSA_do_verify" and
|
||||
result.asIndirectExpr() = this.getArgument(3) and
|
||||
type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
this.getTarget().getName() = "DSA_do_sign" and
|
||||
result.asIndirectExpr() = this and
|
||||
type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to `EVP_VerifyInit` or `EVP_VerifyInit_ex`
|
||||
* - int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
|
||||
* - int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type);
|
||||
*/
|
||||
class EVP_VerifyInitCall extends OperationStep {
|
||||
EVP_VerifyInitCall() { this.getTarget().getName() in ["EVP_VerifyInit", "EVP_VerifyInit_ex"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_VerifyUpdate`
|
||||
* - int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt);
|
||||
*/
|
||||
class EVP_VerifyUpdateCall extends OperationStep {
|
||||
EVP_VerifyUpdateCall() { this.getTarget().getName() = "EVP_VerifyUpdate" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(2) and type = PlaintextSizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_VerifyFinal` or `EVP_VerifyFinal_ex`
|
||||
* - int EVP_VerifyFinal_ex(EVP_MD_CTX *ctx, const unsigned char *sigbuf,
|
||||
* unsigned int siglen, EVP_PKEY *pkey,
|
||||
* OSSL_LIB_CTX *libctx, const char *propq);
|
||||
*- int EVP_VerifyFinal(EVP_MD_CTX *ctx, unsigned char *sigbuf, unsigned int siglen,
|
||||
* EVP_PKEY *pkey); *
|
||||
*/
|
||||
class EVP_VerifyFinalCall extends SignatureFinalOperation {
|
||||
EVP_VerifyFinalCall() { this.getTarget().getName() in ["EVP_VerifyFinal", "EVP_VerifyFinal_ex"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(3) and type = KeyIO()
|
||||
or
|
||||
result.asIndirectExpr() = this.getArgument(4) and type = OsslLibContextIO()
|
||||
// TODO: arg 5 propq?
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
||||
result.asExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of a signature operation.
|
||||
* This is an OpenSSL specific class that extends the base SignatureOperationInstance.
|
||||
* An EVP signature operation instance.
|
||||
*/
|
||||
class OpenSslSignatureOperationInstance extends Crypto::SignatureOperationInstance instanceof SignatureFinalOperation
|
||||
class EvpSignatureOperationInstance extends Crypto::SignatureOperationInstance instanceof EvpSignatureFinalOperation
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
@@ -649,7 +217,7 @@ class OpenSslSignatureOperationInstance extends Crypto::SignatureOperationInstan
|
||||
* Signing, verification or unknown.
|
||||
*/
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
// NOTE: if this KeyOperationSubtype does not match initialization call's KeyOperationSubtype then we found a bug
|
||||
// TODO: if this KeyOperationSubtype does not match initialization call's KeyOperationSubtype then we found a bug
|
||||
if super.getTarget().getName().toLowerCase().matches("%sign%")
|
||||
then result instanceof Crypto::TSignMode
|
||||
else
|
||||
@@ -659,70 +227,14 @@ class OpenSslSignatureOperationInstance extends Crypto::SignatureOperationInstan
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
||||
// some signing operations may have explicit nonce generators
|
||||
super.getDominatingInitializersToStep(IVorNonceIO()).getInput(IVorNonceIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() {
|
||||
super.getDominatingInitializersToStep(SignatureIO()).getInput(SignatureIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
super.getOutputStepFlowingToStep(SignatureIO()).getOutput(SignatureIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||
super
|
||||
.getDominatingInitializersToStep(HashAlgorithmIO())
|
||||
.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
||||
or
|
||||
// Handle cases where the hash is set through the primary algorithm
|
||||
// RSA-SHA256 for example
|
||||
// NOTE: assuming the hash would not be overridden, or if it is it is undefined
|
||||
// i.e., if the above dominating initializer exists and the primary algorithm
|
||||
// specifies a hash, consider both valid hash AVCs.
|
||||
// TODO: can this behavior be build into the get dominating initializers?
|
||||
super.getPrimaryAlgorithmValueConsumer() = result and
|
||||
exists(OpenSslAlgorithmInstance i |
|
||||
i.getAvc() = result and i instanceof Crypto::HashAlgorithmInstance
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasHashAlgorithmConsumer() {
|
||||
exists(super.getDominatingInitializersToStep(HashAlgorithmIO()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for signature or MAC operation instances.
|
||||
* This is an OpenSSL specific class that extends the base SignatureOrMacOperationInstance.
|
||||
*/
|
||||
class OpenSslSignatureOrMacOperationInstance extends Crypto::SignatureOrMacOperationInstance instanceof SignatureOrMacFinalOperation
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
// TODO: some signing operations may have explicit nonce generators
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Signing, verification or unknown.
|
||||
* Keys provided in the initialization call or in a context are found by this method.
|
||||
* Keys in explicit arguments are found by overridden methods in extending classes.
|
||||
*/
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
result instanceof Crypto::TSignMode or result instanceof Crypto::TMacMode
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
||||
// some signing operations may have explicit nonce generators
|
||||
super.getDominatingInitializersToStep(IVorNonceIO()).getInput(IVorNonceIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
|
||||
}
|
||||
@@ -735,24 +247,14 @@ class OpenSslSignatureOrMacOperationInstance extends Crypto::SignatureOrMacOpera
|
||||
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: only signing operations for now, change when verificaiton is added
|
||||
*/
|
||||
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() { none() }
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||
super
|
||||
.getDominatingInitializersToStep(HashAlgorithmIO())
|
||||
.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
||||
or
|
||||
// Handle cases where the hash is set through the primary algorithm
|
||||
// RSA-SHA256 for example
|
||||
// NOTE: assuming the hash would not be overridden, or if it is it is undefined
|
||||
// i.e., if the above dominating initializer exists and the primary algorithm
|
||||
// specifies a hash, consider both valid hash AVCs.
|
||||
// TODO: can this behavior be build into the get dominating initializers?
|
||||
super.getPrimaryAlgorithmValueConsumer() = result and
|
||||
exists(OpenSslAlgorithmInstance i |
|
||||
i.getAvc() = result and i instanceof Crypto::HashAlgorithmInstance
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasHashAlgorithmConsumer() {
|
||||
exists(super.getDominatingInitializersToStep(HashAlgorithmIO()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,11 +298,10 @@ private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, bool
|
||||
else
|
||||
if strictlyNegative(x)
|
||||
then upper = true and delta = -1
|
||||
else (
|
||||
negative(x) and
|
||||
upper = true and
|
||||
delta = 0
|
||||
)
|
||||
else
|
||||
if negative(x)
|
||||
then upper = true and delta = 0
|
||||
else none()
|
||||
)
|
||||
or
|
||||
exists(Operand x |
|
||||
@@ -322,11 +321,10 @@ private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, bool
|
||||
else
|
||||
if strictlyNegative(x)
|
||||
then upper = false and delta = 1
|
||||
else (
|
||||
negative(x) and
|
||||
upper = false and
|
||||
delta = 0
|
||||
)
|
||||
else
|
||||
if negative(x)
|
||||
then upper = false and delta = 0
|
||||
else none()
|
||||
)
|
||||
or
|
||||
i.(RemInstruction).getRightOperand() = op and positive(op) and delta = -1 and upper = true
|
||||
@@ -412,7 +410,7 @@ private predicate boundFlowStepPhi(
|
||||
or
|
||||
exists(IRGuardCondition guard, boolean testIsTrue |
|
||||
guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and
|
||||
guard.controlsBranchEdge(op2.getPredecessorBlock(), op2.getUse().getBlock(), testIsTrue) and
|
||||
guard.controlsEdge(op2.getPredecessorBlock(), op2.getUse().getBlock(), testIsTrue) and
|
||||
reason = TCondReason(guard)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 5.6.2-dev
|
||||
version: 5.5.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -198,7 +198,7 @@ class ConceptIdExpr extends Expr, @concept_id {
|
||||
final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) }
|
||||
|
||||
/**
|
||||
* Gets template argument at index `index` passed to the concept, if any.
|
||||
* Gets the `i`th template argument passed to the concept.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
@@ -219,7 +219,7 @@ class ConceptIdExpr extends Expr, @concept_id {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of the template argument value at index `index` passed to the concept, if any.
|
||||
* Gets the kind of the `i`th template argument value passed to the concept.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
|
||||
@@ -223,8 +223,8 @@ class Declaration extends Locatable, @declaration {
|
||||
final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) }
|
||||
|
||||
/**
|
||||
* Gets the template argument at index `index` used to instantiate this declaration from a
|
||||
* template, if any.
|
||||
* Gets the `i`th template argument used to instantiate this declaration from a
|
||||
* template.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
@@ -245,9 +245,9 @@ class Declaration extends Locatable, @declaration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the template argument value at index `index` used to instantiate this declaration
|
||||
* from a template. When called on a template, this will return the template
|
||||
* parameter value at index `index` if it exists.
|
||||
* Gets the `i`th template argument value used to instantiate this declaration
|
||||
* from a template. When called on a template, this will return the `i`th template
|
||||
* parameter value if it exists.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
|
||||
@@ -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() }
|
||||
|
||||
/**
|
||||
|
||||
@@ -877,7 +877,7 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the char type required by the `n`th conversion specifier.
|
||||
* Gets the char type required by the nth conversion specifier.
|
||||
* - in the base case this is the default for the formatting function
|
||||
* (e.g. `char` for `printf`, `char` or `wchar_t` for `wprintf`).
|
||||
* - the `%C` format character reverses wideness.
|
||||
@@ -922,7 +922,7 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string type required by the `n`th conversion specifier.
|
||||
* Gets the string type required by the nth conversion specifier.
|
||||
* - in the base case this is the default for the formatting function
|
||||
* (e.g. `char *` for `printf`, `char *` or `wchar_t *` for `wprintf`).
|
||||
* - the `%S` format character reverses wideness on some platforms.
|
||||
|
||||
@@ -101,7 +101,7 @@ predicate postDominates(ControlFlowNode postDominator, ControlFlowNode node) {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Holds if `dom` is an immediate dominator of `node` in the control-flow
|
||||
* Holds if `dominator` is an immediate dominator of `node` in the control-flow
|
||||
* graph of basic blocks.
|
||||
*/
|
||||
predicate bbIDominates(BasicBlock dom, BasicBlock node) =
|
||||
@@ -117,7 +117,7 @@ private predicate bb_predecessor(BasicBlock succ, BasicBlock pred) { bb_successo
|
||||
private predicate bb_exit(ExitBasicBlock exit) { any() }
|
||||
|
||||
/**
|
||||
* Holds if `pDom` is an immediate post-dominator of `node` in the control-flow
|
||||
* Holds if `postDominator` is an immediate post-dominator of `node` in the control-flow
|
||||
* graph of basic blocks.
|
||||
*/
|
||||
predicate bbIPostDominates(BasicBlock pDom, BasicBlock node) =
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1042,8 +1042,8 @@ private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2)
|
||||
* - `MicrosoftTryFinallyStmt`: On the edge following the `__finally` block for
|
||||
* the case where an exception was thrown and needs to be propagated.
|
||||
*/
|
||||
DestructorCall getSynthesisedDestructorCallAfterNode(Node node, int index) {
|
||||
synthetic_destructor_call(node, index, result)
|
||||
DestructorCall getSynthesisedDestructorCallAfterNode(Node n, int i) {
|
||||
synthetic_destructor_call(n, i, result)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -834,10 +834,8 @@ class ContentSet instanceof Content {
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -2273,10 +2273,8 @@ class ContentSet instanceof Content {
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -498,9 +498,7 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
|
||||
|
||||
int getArgumentIndex() { result = p.getIndex() }
|
||||
|
||||
override FinalParameterNode getNode() {
|
||||
finalParameterNodeHasParameterAndIndex(result, p, indirectionIndex)
|
||||
}
|
||||
override Node getNode() { finalParameterNodeHasParameterAndIndex(result, p, indirectionIndex) }
|
||||
|
||||
override int getIndirection() { result = indirectionIndex + 1 }
|
||||
|
||||
@@ -1002,7 +1000,7 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
result instanceof FalseEdge
|
||||
}
|
||||
|
||||
class GuardValue = IRGuards::GuardValue;
|
||||
class GuardValue = Boolean;
|
||||
|
||||
class Guard instanceof IRGuards::IRGuardCondition {
|
||||
string toString() { result = super.toString() }
|
||||
@@ -1010,7 +1008,7 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
predicate hasValueBranchEdge(IRCfg::BasicBlock bb1, IRCfg::BasicBlock bb2, GuardValue branch) {
|
||||
exists(EdgeKind kind |
|
||||
super.getBlock() = bb1 and
|
||||
kind = getConditionalEdge(branch.asBooleanValue()) and
|
||||
kind = getConditionalEdge(branch) and
|
||||
bb1.getSuccessor(kind) = bb2
|
||||
)
|
||||
}
|
||||
@@ -1023,7 +1021,7 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, IRCfg::BasicBlock bb, GuardValue branch) {
|
||||
guard.(IRGuards::IRGuardCondition).valueControls(bb, branch)
|
||||
guard.(IRGuards::IRGuardCondition).controls(bb, branch)
|
||||
}
|
||||
|
||||
predicate keepAllPhiInputBackEdges() { any() }
|
||||
@@ -1050,35 +1048,25 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate guardChecksInstr(
|
||||
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, boolean branch,
|
||||
int indirectionIndex
|
||||
private predicate guardChecks(
|
||||
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def,
|
||||
DataFlowIntegrationInput::GuardValue branch, int indirectionIndex
|
||||
) {
|
||||
exists(Node node |
|
||||
nodeHasInstruction(node, instr, indirectionIndex) and
|
||||
guardChecksNode(g, node, branch, indirectionIndex)
|
||||
exists(UseImpl use |
|
||||
guardChecksNode(g, use.getNode(), branch, indirectionIndex) and
|
||||
ssaDefReachesCertainUse(def, use)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate guardChecksWithWrappers(
|
||||
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val,
|
||||
int indirectionIndex
|
||||
) {
|
||||
IRGuards::Guards_v1::ValidationWrapperWithState<int, guardChecksInstr/4>::guardChecksDef(g, def,
|
||||
val, indirectionIndex)
|
||||
}
|
||||
|
||||
Node getABarrierNode(int indirectionIndex) {
|
||||
// Only get the SynthNodes from the shared implementation, as the ExprNodes cannot
|
||||
// be matched on SourceVariable.
|
||||
result.(SsaSynthNode).getSynthNode() =
|
||||
DataFlowIntegrationImpl::BarrierGuardDefWithState<int, guardChecksWithWrappers/4>::getABarrierNode(indirectionIndex)
|
||||
DataFlowIntegrationImpl::BarrierGuardDefWithState<int, guardChecks/4>::getABarrierNode(indirectionIndex)
|
||||
or
|
||||
// Calculate the guarded UseImpls corresponding to ExprNodes directly.
|
||||
exists(
|
||||
DataFlowIntegrationInput::Guard g, IRGuards::GuardValue branch, Definition def, IRBlock bb
|
||||
|
|
||||
guardChecksWithWrappers(g, def, branch, indirectionIndex) and
|
||||
exists(DataFlowIntegrationInput::Guard g, boolean branch, Definition def, IRBlock bb |
|
||||
guardChecks(g, def, branch, indirectionIndex) and
|
||||
exists(UseImpl use |
|
||||
ssaDefReachesCertainUse(def, use) and
|
||||
use.getBlock() = bb and
|
||||
@@ -1136,15 +1124,7 @@ predicate ssaFlow(Node nodeFrom, Node nodeTo) {
|
||||
*/
|
||||
class PhiNode extends Definition instanceof SsaImpl::PhiNode {
|
||||
/** Gets a definition that is an input to this phi node. */
|
||||
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
||||
|
||||
/**
|
||||
* Holds if `input` is an input to this phi node along the edge originating
|
||||
* in `bb`.
|
||||
*/
|
||||
final predicate hasInputFromBlock(Definition input, IRBlock bb) {
|
||||
phiHasInputFromBlock(this, input, bb)
|
||||
}
|
||||
final Definition getAnInput() { phiHasInputFromBlock(this, result, _) }
|
||||
}
|
||||
|
||||
/** An static single assignment (SSA) definition. */
|
||||
@@ -1169,53 +1149,10 @@ class Definition extends SsaImpl::Definition {
|
||||
exists(SourceVariable sv, IRBlock bb, int i, UseImpl use |
|
||||
ssaDefReachesRead(sv, this, bb, i) and
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
use = TDirectUseImpl(result, 0)
|
||||
result = use.getNode().asOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition defines the parameter `p` upon entry into the
|
||||
* enclosing function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isParameterDefinition(Parameter p) {
|
||||
this.getIndirectionIndex() = 0 and
|
||||
getDefImpl(this).getValue().asInstruction().(InitializeParameterInstruction).getParameter() = p
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition defines the `indirectionIndex`'th indirection of
|
||||
* parameter `p` upon entry into the enclosing function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isIndirectParameterDefinition(Parameter p, int indirectionIndex) {
|
||||
this.getIndirectionIndex() = indirectionIndex and
|
||||
indirectionIndex > 0 and
|
||||
getDefImpl(this).getValue().asInstruction().(InitializeParameterInstruction).getParameter() = p
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition defines the implicit `this` parameter upon entry into
|
||||
* the enclosing member function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isThisDefinition() {
|
||||
this.getIndirectionIndex() = 0 and
|
||||
getDefImpl(this).getValue().asInstruction().(InitializeParameterInstruction).hasIndex(-1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition defines the implicit `*this` parameter (i.e., the
|
||||
* indirection of the `this` parameter) upon entry into the enclosing member
|
||||
* function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isIndirectThisDefinition(int indirectionIndex) {
|
||||
this.getIndirectionIndex() = indirectionIndex and
|
||||
indirectionIndex > 0 and
|
||||
getDefImpl(this).getValue().asInstruction().(InitializeParameterInstruction).hasIndex(-1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `Operand` that represents an indirect use of this definition.
|
||||
*
|
||||
@@ -1230,11 +1167,10 @@ class Definition extends SsaImpl::Definition {
|
||||
* value that was defined by the definition.
|
||||
*/
|
||||
Operand getAnIndirectUse(int indirectionIndex) {
|
||||
indirectionIndex > 0 and
|
||||
exists(SourceVariable sv, IRBlock bb, int i, UseImpl use |
|
||||
ssaDefReachesRead(sv, this, bb, i) and
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
use = TDirectUseImpl(result, indirectionIndex)
|
||||
result = use.getNode().asIndirectOperand(indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -52,18 +52,11 @@ class GotoEdge extends EdgeKindImpl, TGotoEdge {
|
||||
final override string toString() { result = "Goto" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A "true" or "false" edge representing a successor of a conditional branch.
|
||||
*/
|
||||
abstract private class BooleanEdgeKindImpl extends EdgeKindImpl { }
|
||||
|
||||
final class BooleanEdge = BooleanEdgeKindImpl;
|
||||
|
||||
/**
|
||||
* A "true" edge, representing the successor of a conditional branch when the
|
||||
* condition is non-zero.
|
||||
*/
|
||||
class TrueEdge extends BooleanEdgeKindImpl, TTrueEdge {
|
||||
class TrueEdge extends EdgeKindImpl, TTrueEdge {
|
||||
final override string toString() { result = "True" }
|
||||
}
|
||||
|
||||
@@ -71,7 +64,7 @@ class TrueEdge extends BooleanEdgeKindImpl, TTrueEdge {
|
||||
* A "false" edge, representing the successor of a conditional branch when the
|
||||
* condition is zero.
|
||||
*/
|
||||
class FalseEdge extends BooleanEdgeKindImpl, TFalseEdge {
|
||||
class FalseEdge extends EdgeKindImpl, TFalseEdge {
|
||||
final override string toString() { result = "False" }
|
||||
}
|
||||
|
||||
@@ -102,48 +95,19 @@ class SehExceptionEdge extends ExceptionEdgeImpl, TSehExceptionEdge {
|
||||
final override string toString() { result = "SEH Exception" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An edge from a `Switch` instruction to one of the cases, or to the default
|
||||
* branch.
|
||||
*/
|
||||
abstract private class SwitchEdgeKindImpl extends EdgeKindImpl {
|
||||
/**
|
||||
* Gets the smallest value of the switch expression for which control will flow along this edge.
|
||||
*/
|
||||
string getMinValue() { none() }
|
||||
|
||||
/**
|
||||
* Gets the largest value of the switch expression for which control will flow along this edge.
|
||||
*/
|
||||
string getMaxValue() { none() }
|
||||
|
||||
/**
|
||||
* Gets the unique value of the switch expression for which control will
|
||||
* flow along this edge, if any.
|
||||
*/
|
||||
final string getValue() { result = unique( | | [this.getMinValue(), this.getMaxValue()]) }
|
||||
|
||||
/** Holds if this edge is the default edge. */
|
||||
predicate isDefault() { none() }
|
||||
}
|
||||
|
||||
final class SwitchEdge = SwitchEdgeKindImpl;
|
||||
|
||||
/**
|
||||
* A "default" edge, representing the successor of a `Switch` instruction when
|
||||
* none of the case values matches the condition value.
|
||||
*/
|
||||
class DefaultEdge extends SwitchEdgeKindImpl, TDefaultEdge {
|
||||
class DefaultEdge extends EdgeKindImpl, TDefaultEdge {
|
||||
final override string toString() { result = "Default" }
|
||||
|
||||
final override predicate isDefault() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A "case" edge, representing the successor of a `Switch` instruction when the
|
||||
* the condition value matches a corresponding `case` label.
|
||||
*/
|
||||
class CaseEdge extends SwitchEdgeKindImpl, TCaseEdge {
|
||||
class CaseEdge extends EdgeKindImpl, TCaseEdge {
|
||||
string minValue;
|
||||
string maxValue;
|
||||
|
||||
@@ -155,9 +119,24 @@ class CaseEdge extends SwitchEdgeKindImpl, TCaseEdge {
|
||||
else result = "Case[" + minValue + ".." + maxValue + "]"
|
||||
}
|
||||
|
||||
final override string getMinValue() { result = minValue }
|
||||
/**
|
||||
* Gets the smallest value of the switch expression for which control will flow along this edge.
|
||||
*/
|
||||
final string getMinValue() { result = minValue }
|
||||
|
||||
final override string getMaxValue() { result = maxValue }
|
||||
/**
|
||||
* Gets the largest value of the switch expression for which control will flow along this edge.
|
||||
*/
|
||||
final string getMaxValue() { result = maxValue }
|
||||
|
||||
/**
|
||||
* Gets the unique value of the switch expression for which control will
|
||||
* flow along this edge, if any.
|
||||
*/
|
||||
final string getValue() {
|
||||
minValue = maxValue and
|
||||
result = minValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1084,12 +1084,6 @@ class BinaryInstruction extends Instruction {
|
||||
or
|
||||
op1 = this.getRightOperand() and op2 = this.getLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the left or right
|
||||
* operand of this binary instruction.
|
||||
*/
|
||||
Instruction getAnInput() { result = this.getLeft() or result = this.getRight() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,14 +129,12 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -146,7 +144,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -156,7 +154,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -164,7 +162,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -173,7 +171,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -184,7 +182,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -208,7 +206,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -231,7 +229,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -244,7 +242,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -256,7 +254,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -279,7 +277,8 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -295,8 +294,10 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,64 +311,68 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1084,12 +1084,6 @@ class BinaryInstruction extends Instruction {
|
||||
or
|
||||
op1 = this.getRightOperand() and op2 = this.getLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the left or right
|
||||
* operand of this binary instruction.
|
||||
*/
|
||||
Instruction getAnInput() { result = this.getLeft() or result = this.getRight() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,14 +129,12 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -146,7 +144,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -156,7 +154,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -164,7 +162,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -173,7 +171,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -184,7 +182,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -208,7 +206,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -231,7 +229,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -244,7 +242,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -256,7 +254,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -279,7 +277,8 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -295,8 +294,10 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,64 +311,68 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ CppType getEllipsisVariablePRValueType() {
|
||||
CppType getEllipsisVariableGLValueType() { result = getTypeForGLValue(any(UnknownType t)) }
|
||||
|
||||
/**
|
||||
* Holds if the function `func` returns a value, as opposed to returning `void`.
|
||||
* Holds if the function returns a value, as opposed to returning `void`.
|
||||
*/
|
||||
predicate hasReturnValue(Function func) { not func.getUnspecifiedType() instanceof VoidType }
|
||||
|
||||
|
||||
@@ -601,7 +601,7 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
|
||||
* The IR translation of an implicit `return` statement generated by the extractor to handle control
|
||||
* flow that reaches the end of a non-`void`-returning function body. Such control flow
|
||||
* produces undefined behavior in C++ but not in C. However even in C using the return value is
|
||||
* undefined behavior. We make it return uninitialized memory to get as much flow as possible.
|
||||
* undefined behaviour. We make it return uninitialized memory to get as much flow as possible.
|
||||
*/
|
||||
class TranslatedNoValueReturnStmt extends TranslatedReturnStmt, TranslatedVariableInitialization {
|
||||
TranslatedNoValueReturnStmt() {
|
||||
|
||||
@@ -1084,12 +1084,6 @@ class BinaryInstruction extends Instruction {
|
||||
or
|
||||
op1 = this.getRightOperand() and op2 = this.getLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction whose result provides the value of the left or right
|
||||
* operand of this binary instruction.
|
||||
*/
|
||||
Instruction getAnInput() { result = this.getLeft() or result = this.getRight() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,14 +129,12 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -146,7 +144,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -156,7 +154,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -164,7 +162,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -173,7 +171,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -184,7 +182,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -208,7 +206,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -231,7 +229,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -244,7 +242,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -256,7 +254,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -279,7 +277,8 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -295,8 +294,10 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,64 +311,68 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -49,8 +49,7 @@ Type getVariableType(Variable v) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the database contains a `switchCase` label with the specified minimum `minValue`
|
||||
* and maximum `maxValue` value.
|
||||
* Holds if the database contains a `case` label with the specified minimum and maximum value.
|
||||
*/
|
||||
predicate hasCaseEdge(SwitchCase switchCase, string minValue, string maxValue) {
|
||||
minValue = switchCase.getExpr().getFullyConverted().getValue() and
|
||||
|
||||
@@ -371,7 +371,7 @@ class FunctionOutput extends TFunctionOutput {
|
||||
/**
|
||||
* Holds if this is the output value pointed to by a pointer parameter to a function, or the
|
||||
* output value referred to by a reference parameter to a function, where the parameter has
|
||||
* index `i`.
|
||||
* index `index`.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
@@ -389,7 +389,7 @@ class FunctionOutput extends TFunctionOutput {
|
||||
/**
|
||||
* Holds if this is the output value pointed to by a pointer parameter (through `ind` number
|
||||
* of indirections) to a function, or the output value referred to by a reference parameter to
|
||||
* a function, where the parameter has index `i`.
|
||||
* a function, where the parameter has index `index`.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
|
||||
@@ -307,12 +307,13 @@ class SemStoreExpr extends SemUnaryExpr {
|
||||
}
|
||||
|
||||
class SemConditionalExpr extends SemKnownExpr {
|
||||
SemExpr condition;
|
||||
SemExpr trueResult;
|
||||
SemExpr falseResult;
|
||||
|
||||
SemConditionalExpr() {
|
||||
opcode instanceof Opcode::Conditional and
|
||||
Specific::conditionalExpr(this, type, any(SemExpr condition), trueResult, falseResult)
|
||||
Specific::conditionalExpr(this, type, condition, trueResult, falseResult)
|
||||
}
|
||||
|
||||
final SemExpr getBranchExpr(boolean branch) {
|
||||
|
||||
@@ -259,7 +259,7 @@ module SemanticExprConfig {
|
||||
}
|
||||
|
||||
predicate guardHasBranchEdge(Guard guard, BasicBlock bb1, BasicBlock bb2, boolean branch) {
|
||||
guard.controlsBranchEdge(bb1, bb2, branch)
|
||||
guard.controlsEdge(bb1, bb2, branch)
|
||||
}
|
||||
|
||||
Guard comparisonGuard(Expr e) { getSemanticExpr(result) = e }
|
||||
|
||||
@@ -21,9 +21,7 @@ class FileWrite extends Expr {
|
||||
Expr getDest() { fileWrite(this, _, result) }
|
||||
|
||||
/**
|
||||
* Gets the conversion character from `source` for this write, if it exists and is known.
|
||||
* For example in the following code the write of `value1` has conversion character `"s"`, whereas
|
||||
* the write of `value2` has no conversion specifier.
|
||||
* Gets the conversion character for this write, if it exists and is known. For example in the following code the write of `value1` has conversion character `"s"`, whereas the write of `value2` has no conversion specifier.
|
||||
* ```
|
||||
* fprintf(file, "%s", value1);
|
||||
* stream << value2;
|
||||
|
||||
@@ -191,19 +191,11 @@ module BoostorgAsio {
|
||||
class SslContextClass extends Class {
|
||||
SslContextClass() { this.getQualifiedName() = "boost::asio::ssl::context" }
|
||||
|
||||
/**
|
||||
* Gets a constructor call, if any.
|
||||
*/
|
||||
ConstructorCall getAConstructorCall() {
|
||||
ConstructorCall getAContructorCall() {
|
||||
this.getAConstructor().getACallToThisFunction() = result and
|
||||
not result.getLocation().getFile().toString().matches("%/boost/asio/%") and
|
||||
result.fromSource()
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAConstructorCall` instead.
|
||||
*/
|
||||
deprecated ConstructorCall getAContructorCall() { result = this.getAConstructorCall() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,7 +368,7 @@ module BoostorgAsio {
|
||||
*/
|
||||
default predicate isSink(DataFlow::Node sink) {
|
||||
exists(ConstructorCall cc, SslContextClass c, Expr e | e = sink.asExpr() |
|
||||
c.getAConstructorCall() = cc and
|
||||
c.getAContructorCall() = cc and
|
||||
cc.getArgument(0) = e
|
||||
)
|
||||
}
|
||||
@@ -476,7 +468,7 @@ module BoostorgAsio {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(SslContextClass c, ConstructorCall cc |
|
||||
cc = source.asExpr() and
|
||||
c.getAConstructorCall() = cc
|
||||
c.getAContructorCall() = cc
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -164,17 +164,12 @@ predicate valueOccurrenceCount(string value, int n) {
|
||||
n > 20
|
||||
}
|
||||
|
||||
predicate occurrenceCount(Literal lit, string value, int n) {
|
||||
predicate occurenceCount(Literal lit, string value, int n) {
|
||||
valueOccurrenceCount(value, n) and
|
||||
value = lit.getValue() and
|
||||
nonTrivialValue(_, lit)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `occurrenceCount` instead.
|
||||
*/
|
||||
deprecated predicate occurenceCount = occurrenceCount/3;
|
||||
|
||||
/*
|
||||
* Literals repeated frequently
|
||||
*/
|
||||
@@ -183,7 +178,7 @@ predicate check(Literal lit, string value, int n, File f) {
|
||||
// Check that the literal is nontrivial
|
||||
not trivial(lit) and
|
||||
// Check that it is repeated a number of times
|
||||
occurrenceCount(lit, value, n) and
|
||||
occurenceCount(lit, value, n) and
|
||||
n > 20 and
|
||||
f = lit.getFile() and
|
||||
// Exclude generated files
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user