mirror of
https://github.com/github/codeql.git
synced 2026-04-14 19:44:03 +02:00
Merge branch 'main' into post-release-prep/codeql-cli-2.25.2
This commit is contained in:
@@ -27,7 +27,7 @@ bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.2.2-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.47.0")
|
||||
bazel_dep(name = "gazelle", version = "0.50.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
|
||||
bazel_dep(name = "googletest", version = "1.17.0.bcr.2")
|
||||
bazel_dep(name = "rules_rust", version = "0.69.0")
|
||||
|
||||
@@ -26,10 +26,23 @@ string permissionsForJob(Job job) {
|
||||
"{" + concat(string permission | permission = jobNeedsPermission(job) | permission, ", ") + "}"
|
||||
}
|
||||
|
||||
predicate jobHasPermissions(Job job) {
|
||||
exists(job.getPermissions())
|
||||
or
|
||||
exists(job.getEnclosingWorkflow().getPermissions())
|
||||
or
|
||||
// The workflow is reusable and cannot be triggered in any other way; check callers
|
||||
exists(ReusableWorkflow r | r = job.getEnclosingWorkflow() |
|
||||
not exists(Event e | e = r.getOn().getAnEvent() | e.getName() != "workflow_call") and
|
||||
forall(Job caller | caller = job.getEnclosingWorkflow().(ReusableWorkflow).getACaller() |
|
||||
jobHasPermissions(caller)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from Job job, string permissions
|
||||
where
|
||||
not exists(job.getPermissions()) and
|
||||
not exists(job.getEnclosingWorkflow().getPermissions()) and
|
||||
not jobHasPermissions(job) and
|
||||
// exists a trigger event that is not a workflow_call
|
||||
exists(Event e |
|
||||
e = job.getATriggerEvent() and
|
||||
|
||||
@@ -20,6 +20,6 @@ from ArtifactPoisoningFlow::PathNode source, ArtifactPoisoningFlow::PathNode sin
|
||||
where
|
||||
ArtifactPoisoningFlow::flowPath(source, sink) and
|
||||
event = getRelevantEventInPrivilegedContext(sink.getNode())
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential artifact poisoning in $@, which may be controlled by an external user ($@).", sink,
|
||||
sink.getNode().toString(), event, event.getName()
|
||||
select source.getNode(), source, sink,
|
||||
"Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@).",
|
||||
event, event.getName()
|
||||
|
||||
@@ -20,6 +20,5 @@ from ArtifactPoisoningFlow::PathNode source, ArtifactPoisoningFlow::PathNode sin
|
||||
where
|
||||
ArtifactPoisoningFlow::flowPath(source, sink) and
|
||||
inNonPrivilegedContext(sink.getNode().asExpr())
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential artifact poisoning in $@, which may be controlled by an external user.", sink,
|
||||
sink.getNode().toString()
|
||||
select source.getNode(), source, sink,
|
||||
"Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user."
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* Fixed alert messages in `actions/artifact-poisoning/critical` and `actions/artifact-poisoning/medium` as they previously included a redundant placeholder in the alert message that would on occasion contain a long block of yml that makes the alert difficult to understand. Also clarify the wording to make it clear that it is not the artifact that is being poisoned, but instead a potentially untrusted artifact that is consumed. Also change the alert location to be the source, to align more with other queries reporting an artifact (e.g. zipslip) which is more useful.
|
||||
4
actions/ql/src/change-notes/2026-04-02-permissions.md
Normal file
4
actions/ql/src/change-notes/2026-04-02-permissions.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `actions/missing-workflow-permissions` no longer produces false positive results on reusable workflows where all callers set permissions.
|
||||
9
actions/ql/test/query-tests/Security/CWE-275/.github/workflows/perms11.yml
vendored
Normal file
9
actions/ql/test/query-tests/Security/CWE-275/.github/workflows/perms11.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/deploy-pages
|
||||
11
actions/ql/test/query-tests/Security/CWE-275/.github/workflows/perms12.yml
vendored
Normal file
11
actions/ql/test/query-tests/Security/CWE-275/.github/workflows/perms12.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
pages: write
|
||||
|
||||
jobs:
|
||||
call-workflow:
|
||||
uses: ./.github/workflows/perms11.yml
|
||||
@@ -55,21 +55,21 @@ nodes
|
||||
| .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | semmle.label | ./gradlew buildScanPublishPrevious\n |
|
||||
subpaths
|
||||
#select
|
||||
| .github/workflows/artifactpoisoning11.yml:38:11:38:77 | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | .github/workflows/artifactpoisoning11.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning11.yml:38:11:38:77 | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning11.yml:38:11:38:77 | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | .github/workflows/artifactpoisoning11.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning12.yml:38:11:38:25 | python foo/x.py | .github/workflows/artifactpoisoning12.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning12.yml:38:11:38:25 | python foo/x.py | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning12.yml:38:11:38:25 | python foo/x.py | python foo/x.py | .github/workflows/artifactpoisoning12.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning21.yml:19:14:20:21 | sh foo/cmd\n | .github/workflows/artifactpoisoning21.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning21.yml:19:14:20:21 | sh foo/cmd\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning21.yml:19:14:20:21 | sh foo/cmd\n | sh foo/cmd\n | .github/workflows/artifactpoisoning21.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning22.yml:18:14:18:19 | sh cmd | .github/workflows/artifactpoisoning22.yml:13:9:17:6 | Uses Step | .github/workflows/artifactpoisoning22.yml:18:14:18:19 | sh cmd | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning22.yml:18:14:18:19 | sh cmd | sh cmd | .github/workflows/artifactpoisoning22.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning31.yml:19:14:19:22 | ./foo/cmd | .github/workflows/artifactpoisoning31.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning31.yml:19:14:19:22 | ./foo/cmd | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning31.yml:19:14:19:22 | ./foo/cmd | ./foo/cmd | .github/workflows/artifactpoisoning31.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning32.yml:17:14:18:20 | ./bar/cmd\n | .github/workflows/artifactpoisoning32.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning32.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning32.yml:17:14:18:20 | ./bar/cmd\n | ./bar/cmd\n | .github/workflows/artifactpoisoning32.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning33.yml:17:14:18:20 | ./bar/cmd\n | .github/workflows/artifactpoisoning33.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning33.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning33.yml:17:14:18:20 | ./bar/cmd\n | ./bar/cmd\n | .github/workflows/artifactpoisoning33.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning34.yml:20:14:22:23 | npm install\nnpm run lint\n | .github/workflows/artifactpoisoning34.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning34.yml:20:14:22:23 | npm install\nnpm run lint\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning34.yml:20:14:22:23 | npm install\nnpm run lint\n | npm install\nnpm run lint\n | .github/workflows/artifactpoisoning34.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning41.yml:22:14:22:22 | ./foo/cmd | .github/workflows/artifactpoisoning41.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning41.yml:22:14:22:22 | ./foo/cmd | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning41.yml:22:14:22:22 | ./foo/cmd | ./foo/cmd | .github/workflows/artifactpoisoning41.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning42.yml:22:14:22:18 | ./cmd | .github/workflows/artifactpoisoning42.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning42.yml:22:14:22:18 | ./cmd | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning42.yml:22:14:22:18 | ./cmd | ./cmd | .github/workflows/artifactpoisoning42.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | sed -f config foo.md > bar.md\n | .github/workflows/artifactpoisoning71.yml:4:5:4:16 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | python test.py | .github/workflows/artifactpoisoning81.yml:3:5:3:23 | pull_request_target | pull_request_target |
|
||||
| .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | Uses Step | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | make snapshot | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | .github/workflows/artifactpoisoning96.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | npm install | .github/workflows/artifactpoisoning96.yml:2:3:2:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | .github/workflows/artifactpoisoning101.yml:4:3:4:21 | pull_request_target | pull_request_target |
|
||||
| .github/workflows/test18.yml:36:15:40:58 | Uses Step | .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Uses Step | .github/workflows/test18.yml:3:5:3:16 | workflow_run | workflow_run |
|
||||
| .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | ./gradlew buildScanPublishPrevious\n | .github/workflows/test25.yml:2:3:2:14 | workflow_run | workflow_run |
|
||||
| .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
|
||||
| .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning11.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning11.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning11.yml:38:11:38:77 | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning11.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning12.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning12.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning12.yml:38:11:38:25 | python foo/x.py | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning12.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning21.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning21.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning21.yml:19:14:20:21 | sh foo/cmd\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning21.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning22.yml:13:9:17:6 | Uses Step | .github/workflows/artifactpoisoning22.yml:13:9:17:6 | Uses Step | .github/workflows/artifactpoisoning22.yml:18:14:18:19 | sh cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning22.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning31.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning31.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning31.yml:19:14:19:22 | ./foo/cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning31.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning32.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning32.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning32.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning32.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning33.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning33.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning33.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning33.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning34.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning34.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning34.yml:20:14:22:23 | npm install\nnpm run lint\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning34.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning41.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning41.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning41.yml:22:14:22:22 | ./foo/cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning41.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning42.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning42.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning42.yml:22:14:22:18 | ./cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning42.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning71.yml:4:5:4:16 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning81.yml:3:5:3:23 | pull_request_target | pull_request_target |
|
||||
| .github/workflows/artifactpoisoning96.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning96.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning96.yml:2:3:2:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning101.yml:4:3:4:21 | pull_request_target | pull_request_target |
|
||||
| .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/test18.yml:3:5:3:16 | workflow_run | workflow_run |
|
||||
| .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/test25.yml:2:3:2:14 | workflow_run | workflow_run |
|
||||
|
||||
@@ -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
|
||||
|
||||
4
cpp/ql/lib/change-notes/2026-04-07-autoconf.md
Normal file
4
cpp/ql/lib/change-notes/2026-04-07-autoconf.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a subclass `AutoconfConfigureTestFile` of `ConfigurationTestFile` that represents files created by GNU autoconf configure scripts to test the build configuration.
|
||||
@@ -42,3 +42,10 @@ class MesonPrivateTestFile extends ConfigurationTestFile {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A file created by a GNU autoconf configure script to test the system configuration.
|
||||
*/
|
||||
class AutoconfConfigureTestFile extends ConfigurationTestFile {
|
||||
AutoconfConfigureTestFile() { this.getBaseName().regexpMatch("conftest[0-9]*\\.c(pp)?") }
|
||||
}
|
||||
|
||||
@@ -459,6 +459,13 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
*/
|
||||
int getConvSpecOffset(int n) { result = this.getFormat().indexOf("%", n, 0) }
|
||||
|
||||
/**
|
||||
* Gets the nth conversion specifier string.
|
||||
*/
|
||||
private string getConvSpecString(int n) {
|
||||
n >= 0 and result = "%" + this.getFormat().splitAt("%", n + 1)
|
||||
}
|
||||
|
||||
/*
|
||||
* Each of these predicates gets a regular expressions to match each individual
|
||||
* parts of a conversion specifier.
|
||||
@@ -524,22 +531,20 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
int n, string spec, string params, string flags, string width, string prec, string len,
|
||||
string conv
|
||||
) {
|
||||
exists(int offset, string fmt, string rst, string regexp |
|
||||
offset = this.getConvSpecOffset(n) and
|
||||
fmt = this.getFormat() and
|
||||
rst = fmt.substring(offset, fmt.length()) and
|
||||
exists(string convSpec, string regexp |
|
||||
convSpec = this.getConvSpecString(n) and
|
||||
regexp = this.getConvSpecRegexp() and
|
||||
(
|
||||
spec = rst.regexpCapture(regexp, 1) and
|
||||
params = rst.regexpCapture(regexp, 2) and
|
||||
flags = rst.regexpCapture(regexp, 3) and
|
||||
width = rst.regexpCapture(regexp, 4) and
|
||||
prec = rst.regexpCapture(regexp, 5) and
|
||||
len = rst.regexpCapture(regexp, 6) and
|
||||
conv = rst.regexpCapture(regexp, 7)
|
||||
spec = convSpec.regexpCapture(regexp, 1) and
|
||||
params = convSpec.regexpCapture(regexp, 2) and
|
||||
flags = convSpec.regexpCapture(regexp, 3) and
|
||||
width = convSpec.regexpCapture(regexp, 4) and
|
||||
prec = convSpec.regexpCapture(regexp, 5) and
|
||||
len = convSpec.regexpCapture(regexp, 6) and
|
||||
conv = convSpec.regexpCapture(regexp, 7)
|
||||
or
|
||||
spec = rst.regexpCapture(regexp, 1) and
|
||||
not exists(rst.regexpCapture(regexp, 2)) and
|
||||
spec = convSpec.regexpCapture(regexp, 1) and
|
||||
not exists(convSpec.regexpCapture(regexp, 2)) and
|
||||
params = "" and
|
||||
flags = "" and
|
||||
width = "" and
|
||||
@@ -554,12 +559,10 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
* Gets the nth conversion specifier (including the initial `%`).
|
||||
*/
|
||||
string getConvSpec(int n) {
|
||||
exists(int offset, string fmt, string rst, string regexp |
|
||||
offset = this.getConvSpecOffset(n) and
|
||||
fmt = this.getFormat() and
|
||||
rst = fmt.substring(offset, fmt.length()) and
|
||||
exists(string convSpec, string regexp |
|
||||
convSpec = this.getConvSpecString(n) and
|
||||
regexp = this.getConvSpecRegexp() and
|
||||
result = rst.regexpCapture(regexp, 1)
|
||||
result = convSpec.regexpCapture(regexp, 1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -194,6 +194,13 @@ class ScanfFormatLiteral extends Expr {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nth conversion specifier string.
|
||||
*/
|
||||
private string getConvSpecString(int n) {
|
||||
n >= 0 and result = "%" + this.getFormat().splitAt("%", n + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the regular expression to match each individual part of a conversion specifier.
|
||||
*/
|
||||
@@ -227,16 +234,14 @@ class ScanfFormatLiteral extends Expr {
|
||||
* specifier.
|
||||
*/
|
||||
predicate parseConvSpec(int n, string spec, string width, string len, string conv) {
|
||||
exists(int offset, string fmt, string rst, string regexp |
|
||||
offset = this.getConvSpecOffset(n) and
|
||||
fmt = this.getFormat() and
|
||||
rst = fmt.substring(offset, fmt.length()) and
|
||||
exists(string convSpec, string regexp |
|
||||
convSpec = this.getConvSpecString(n) and
|
||||
regexp = this.getConvSpecRegexp() and
|
||||
(
|
||||
spec = rst.regexpCapture(regexp, 1) and
|
||||
width = rst.regexpCapture(regexp, 2) and
|
||||
len = rst.regexpCapture(regexp, 3) and
|
||||
conv = rst.regexpCapture(regexp, 4)
|
||||
spec = convSpec.regexpCapture(regexp, 1) and
|
||||
width = convSpec.regexpCapture(regexp, 2) and
|
||||
len = convSpec.regexpCapture(regexp, 3) and
|
||||
conv = convSpec.regexpCapture(regexp, 4)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,11 +6,15 @@
|
||||
*
|
||||
* The extensible relations have the following columns:
|
||||
* - Sources:
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind`
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
|
||||
* - Sinks:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; kind`
|
||||
* `namespace; type; subtypes; name; signature; ext; input; kind; provenance`
|
||||
* - Summaries:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; output; kind`
|
||||
* `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance`
|
||||
* - Barriers:
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
|
||||
* - BarrierGuards:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; acceptingValue; kind; provenance`
|
||||
*
|
||||
* The interpretation of a row is similar to API-graphs with a left-to-right
|
||||
* reading.
|
||||
@@ -87,11 +91,23 @@
|
||||
* value, and
|
||||
* - flow from the _second_ indirection of the 0th argument to the first
|
||||
* indirection of the return value, etc.
|
||||
* 8. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* 8. The `acceptingValue` column of barrier guard models specifies the condition
|
||||
* under which the guard blocks flow. It can be one of "true" or "false". In
|
||||
* the future "no-exception", "not-zero", "null", "not-null" may be supported.
|
||||
* 9. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* which classes the interpreted elements should be added. For example, for
|
||||
* sources "remote" indicates a default remote flow source, and for summaries
|
||||
* "taint" indicates a default additional taint step and "value" indicates a
|
||||
* globally applicable value-preserving step.
|
||||
* 10. The `provenance` column is a tag to indicate the origin and verification of a model.
|
||||
* The format is {origin}-{verification} or just "manual" where the origin describes
|
||||
* the origin of the model and verification describes how the model has been verified.
|
||||
* Some examples are:
|
||||
* - "df-generated": The model has been generated by the model generator tool.
|
||||
* - "df-manual": The model has been generated by the model generator and verified by a human.
|
||||
* - "manual": The model has been written by hand.
|
||||
* This information is used in a heuristic for dataflow analysis to determine, if a
|
||||
* model or source code should be used for determining flow.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
@@ -931,13 +947,13 @@ private module Cached {
|
||||
|
||||
private predicate barrierGuardChecks(IRGuardCondition g, Expr e, boolean gv, TKindModelPair kmp) {
|
||||
exists(
|
||||
SourceSinkInterpretationInput::InterpretNode n, Public::AcceptingValue acceptingvalue,
|
||||
SourceSinkInterpretationInput::InterpretNode n, Public::AcceptingValue acceptingValue,
|
||||
string kind, string model
|
||||
|
|
||||
isBarrierGuardNode(n, acceptingvalue, kind, model) and
|
||||
isBarrierGuardNode(n, acceptingValue, kind, model) and
|
||||
n.asNode().asExpr() = e and
|
||||
kmp = TMkPair(kind, model) and
|
||||
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
|
||||
gv = convertAcceptingValue(acceptingValue).asBooleanValue() and
|
||||
n.asNode().(Private::ArgumentNode).getCall().asCallInstruction() = g
|
||||
)
|
||||
}
|
||||
@@ -954,14 +970,14 @@ private module Cached {
|
||||
) {
|
||||
exists(
|
||||
SourceSinkInterpretationInput::InterpretNode interpretNode,
|
||||
Public::AcceptingValue acceptingvalue, string kind, string model, int indirectionIndex,
|
||||
Public::AcceptingValue acceptingValue, string kind, string model, int indirectionIndex,
|
||||
Private::ArgumentNode arg
|
||||
|
|
||||
isBarrierGuardNode(interpretNode, acceptingvalue, kind, model) and
|
||||
isBarrierGuardNode(interpretNode, acceptingValue, kind, model) and
|
||||
arg = interpretNode.asNode() and
|
||||
arg.asIndirectExpr(indirectionIndex) = e and
|
||||
kmp = MkKindModelPairIntPair(TMkPair(kind, model), indirectionIndex) and
|
||||
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
|
||||
gv = convertAcceptingValue(acceptingValue).asBooleanValue() and
|
||||
arg.getCall().asCallInstruction() = g
|
||||
)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ extensible predicate barrierModel(
|
||||
*/
|
||||
extensible predicate barrierGuardModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string acceptingvalue, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
string input, string acceptingValue, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -162,13 +162,13 @@ module SourceSinkInterpretationInput implements
|
||||
}
|
||||
|
||||
predicate barrierGuardElement(
|
||||
Element e, string input, Public::AcceptingValue acceptingvalue, string kind,
|
||||
Element e, string input, Public::AcceptingValue acceptingValue, string kind,
|
||||
Public::Provenance provenance, string model
|
||||
) {
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingvalue, kind,
|
||||
barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingValue, kind,
|
||||
provenance, model) and
|
||||
e = interpretElement(package, type, subtypes, name, signature, ext)
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.1
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/integer-multiplication-cast-to-long
|
||||
* @tags reliability
|
||||
* security
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/wrong-type-format-argument
|
||||
* @tags reliability
|
||||
* correctness
|
||||
|
||||
@@ -14,6 +14,9 @@ function may behave unpredictably.</p>
|
||||
<p>This may indicate a misspelled function name, or that the required header containing
|
||||
the function declaration has not been included.</p>
|
||||
|
||||
<p>Note: This query is not compatible with <code>build mode: none</code> databases, and produces
|
||||
no results on those databases.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Provide an explicit declaration of the function before invoking it.</p>
|
||||
@@ -26,4 +29,4 @@ the function declaration has not been included.</p>
|
||||
<references>
|
||||
<li>SEI CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL31-C.+Declare+identifiers+before+using+them">DCL31-C. Declare identifiers before using them</a></li>
|
||||
</references>
|
||||
</qhelp>
|
||||
</qhelp>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* may lead to unpredictable behavior.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/implicit-function-declaration
|
||||
* @tags correctness
|
||||
* maintainability
|
||||
@@ -17,6 +17,11 @@ import TooFewArguments
|
||||
import TooManyArguments
|
||||
import semmle.code.cpp.commons.Exclusions
|
||||
|
||||
/*
|
||||
* This query is not compatible with build mode: none databases, and produces
|
||||
* no results on those databases.
|
||||
*/
|
||||
|
||||
predicate locInfo(Locatable e, File file, int line, int col) {
|
||||
e.getFile() = file and
|
||||
e.getLocation().getStartLine() = line and
|
||||
@@ -39,6 +44,7 @@ predicate isCompiledAsC(File f) {
|
||||
from FunctionDeclarationEntry fdeIm, FunctionCall fc
|
||||
where
|
||||
isCompiledAsC(fdeIm.getFile()) and
|
||||
not any(Compilation c).buildModeNone() and
|
||||
not isFromMacroDefinition(fc) and
|
||||
fdeIm.isImplicit() and
|
||||
sameLocation(fdeIm, fc) and
|
||||
|
||||
@@ -79,9 +79,7 @@ private predicate hasZeroParamDecl(Function f) {
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
private predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
exists(File src | src.compiledAsC() | src.getAnIncludedFile*() = f)
|
||||
}
|
||||
|
||||
predicate mistypedFunctionArguments(FunctionCall fc, Function f, Parameter p) {
|
||||
|
||||
@@ -28,9 +28,7 @@ private predicate hasZeroParamDecl(Function f) {
|
||||
|
||||
/* Holds if this file (or header) was compiled as a C file. */
|
||||
private predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
exists(File src | src.compiledAsC() | src.getAnIncludedFile*() = f)
|
||||
}
|
||||
|
||||
/** Holds if `fc` is a call to `f` with too few arguments. */
|
||||
|
||||
@@ -19,9 +19,7 @@ private predicate hasZeroParamDecl(Function f) {
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
private predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
exists(File src | src.compiledAsC() | src.getAnIncludedFile*() = f)
|
||||
}
|
||||
|
||||
predicate tooManyArguments(FunctionCall fc, Function f) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.8
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-190
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.8
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/suspicious-add-sizeof
|
||||
* @tags security
|
||||
* external/cwe/cwe-468
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Implicit function declaration" (`cpp/implicit-function-declaration`) query no longer produces results on `build mode: none` databases. These results were found to be very noisy and fundamentally imprecise in this mode.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Comparison of narrow type with wide type in loop condition" (`cpp/comparison-with-wider-type`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Implicit function declaration" (`cpp/implicit-function-declaration`) query has been upgraded to `high` precision.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Suspicious add with sizeof" (`cpp/suspicious-add-sizeof`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Wrong type of arguments to formatting function" (`cpp/wrong-type-format-argument`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
|
||||
@@ -0,0 +1,2 @@
|
||||
| conftest.c.c:4:3:4:8 | call to strlen | This expression has no effect (because $@ has no external side effects). | conftest.h:3:8:3:13 | strlen | strlen |
|
||||
| conftest_abc.c:4:3:4:8 | call to strlen | This expression has no effect (because $@ has no external side effects). | conftest.h:3:8:3:13 | strlen | strlen |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Likely Typos/ExprHasNoEffect.ql
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "conftest.h"
|
||||
|
||||
int main2() {
|
||||
strlen(""); // GOOD: conftest files are ignored
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "conftest.h"
|
||||
|
||||
int main3() {
|
||||
strlen(""); // BAD: not a `conftest` file, as `conftest` is not directly followed by the extension or a sequence of numbers.
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "conftest.h"
|
||||
|
||||
int main4() {
|
||||
strlen(""); // GOOD: conftest files are ignored
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
typedef long long size_t;
|
||||
|
||||
size_t strlen(const char *s);
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "conftest.h"
|
||||
|
||||
int main5() {
|
||||
strlen(""); // GOOD: conftest files are ignored
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "conftest.h"
|
||||
|
||||
int main1() {
|
||||
strlen(""); // BAD: not a `conftest` file, as `conftest` is not directly followed by the extension or a sequence of numbers.
|
||||
return 0;
|
||||
}
|
||||
@@ -9,5 +9,5 @@
|
||||
import csharp
|
||||
|
||||
from IntegerLiteral literal
|
||||
where literal.getValue().toInt() = 0
|
||||
where literal.getIntValue() = 0
|
||||
select literal
|
||||
|
||||
@@ -77,7 +77,7 @@ predicate missedAllOpportunity(ForeachStmtGenericEnumerable fes) {
|
||||
// The then case of the if assigns false to something and breaks out of the loop.
|
||||
exists(Assignment a, BoolLiteral bl |
|
||||
a = is.getThen().getAChild*() and
|
||||
bl = a.getRValue() and
|
||||
bl = a.getRightOperand() and
|
||||
bl.toString() = "false"
|
||||
) and
|
||||
is.getThen().getAChild*() instanceof BreakStmt
|
||||
|
||||
4
csharp/ql/lib/change-notes/2026-04-01-getlrvalue.md
Normal file
4
csharp/ql/lib/change-notes/2026-04-01-getlrvalue.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The predicates `get[L|R]Value` in the class `Assignment` have been deprecated. Use `get[Left|Right]Operand` instead.
|
||||
@@ -96,7 +96,7 @@ private class MethodUse extends Use, QualifiableExpr {
|
||||
private class AccessUse extends Access, Use {
|
||||
AccessUse() {
|
||||
not this.getTarget().(Parameter).getCallable() instanceof Accessor and
|
||||
not this = any(LocalVariableDeclAndInitExpr d).getLValue() and
|
||||
not this = any(LocalVariableDeclAndInitExpr d).getLeftOperand() and
|
||||
not this.isImplicit() and
|
||||
not this instanceof MethodAccess and // handled by `MethodUse`
|
||||
not this instanceof TypeAccess and // handled by `TypeMentionUse`
|
||||
|
||||
@@ -235,7 +235,7 @@ private class RefArg extends AssignableAccess {
|
||||
module AssignableInternal {
|
||||
private predicate tupleAssignmentDefinition(AssignExpr ae, Expr leaf) {
|
||||
exists(TupleExpr te |
|
||||
ae.getLValue() = te and
|
||||
ae.getLeftOperand() = te and
|
||||
te.getAnArgument+() = leaf and
|
||||
// `leaf` is either an assignable access or a local variable declaration
|
||||
not leaf instanceof TupleExpr
|
||||
@@ -249,8 +249,8 @@ module AssignableInternal {
|
||||
*/
|
||||
private predicate tupleAssignmentPair(AssignExpr ae, Expr left, Expr right) {
|
||||
tupleAssignmentDefinition(ae, _) and
|
||||
left = ae.getLValue() and
|
||||
right = ae.getRValue()
|
||||
left = ae.getLeftOperand() and
|
||||
right = ae.getRightOperand()
|
||||
or
|
||||
exists(TupleExpr l, TupleExpr r, int i | tupleAssignmentPair(ae, l, r) |
|
||||
left = l.getArgument(i) and
|
||||
@@ -291,7 +291,7 @@ module AssignableInternal {
|
||||
cached
|
||||
newtype TAssignableDefinition =
|
||||
TAssignmentDefinition(Assignment a) {
|
||||
not a.getLValue() instanceof TupleExpr and
|
||||
not a.getLeftOperand() instanceof TupleExpr and
|
||||
not a instanceof AssignCallOperation and
|
||||
not a instanceof AssignCoalesceExpr
|
||||
} or
|
||||
@@ -358,7 +358,7 @@ module AssignableInternal {
|
||||
// Not defined by dispatch in order to avoid too conservative negative recursion error
|
||||
cached
|
||||
AssignableAccess getTargetAccess(AssignableDefinition def) {
|
||||
def = TAssignmentDefinition(any(Assignment a | a.getLValue() = result))
|
||||
def = TAssignmentDefinition(any(Assignment a | a.getLeftOperand() = result))
|
||||
or
|
||||
def = TTupleAssignmentDefinition(_, result)
|
||||
or
|
||||
@@ -381,8 +381,8 @@ module AssignableInternal {
|
||||
tupleAssignmentPair(ae, ac, result)
|
||||
)
|
||||
or
|
||||
exists(Assignment ass | ac = ass.getLValue() |
|
||||
result = ass.getRValue() and
|
||||
exists(Assignment ass | ac = ass.getLeftOperand() |
|
||||
result = ass.getRightOperand() and
|
||||
not ass instanceof AssignOperation
|
||||
)
|
||||
or
|
||||
@@ -527,7 +527,7 @@ module AssignableDefinitions {
|
||||
Assignment getAssignment() { result = a }
|
||||
|
||||
override Expr getSource() {
|
||||
result = a.getRValue() and
|
||||
result = a.getRightOperand() and
|
||||
not a instanceof AddOrRemoveEventExpr
|
||||
}
|
||||
|
||||
|
||||
@@ -232,14 +232,9 @@ private module Identity {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate convTypeArguments(Type fromTypeArgument, Type toTypeArgument, int i) {
|
||||
exists(int j |
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, i) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, j) and
|
||||
i <= j and
|
||||
j <= i
|
||||
|
|
||||
convIdentity(fromTypeArgument, toTypeArgument)
|
||||
)
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, pragma[only_bind_into](i)) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, pragma[only_bind_into](i)) and
|
||||
convIdentity(fromTypeArgument, toTypeArgument)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -718,7 +713,7 @@ private class SignedIntegralConstantExpr extends Expr {
|
||||
}
|
||||
|
||||
private predicate convConstantIntExpr(SignedIntegralConstantExpr e, SimpleType toType) {
|
||||
exists(int n | n = e.getValue().toInt() |
|
||||
exists(int n | n = e.getIntValue() |
|
||||
toType = any(SByteType t | n in [t.minValue() .. t.maxValue()])
|
||||
or
|
||||
toType = any(ByteType t | n in [t.minValue() .. t.maxValue()])
|
||||
@@ -735,7 +730,7 @@ private predicate convConstantIntExpr(SignedIntegralConstantExpr e, SimpleType t
|
||||
|
||||
private predicate convConstantLongExpr(SignedIntegralConstantExpr e) {
|
||||
e.getType() instanceof LongType and
|
||||
e.getValue().toInt() >= 0
|
||||
e.getIntValue() >= 0
|
||||
}
|
||||
|
||||
/** 6.1.10: Implicit reference conversions involving type parameters. */
|
||||
@@ -929,19 +924,16 @@ private module Variance {
|
||||
private predicate convTypeArguments(
|
||||
TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i, TVariance v
|
||||
) {
|
||||
exists(int j |
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, i, _) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, j, _) and
|
||||
i <= j and
|
||||
j <= i
|
||||
|
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, pragma[only_bind_into](i), _) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, pragma[only_bind_into](i), _) and
|
||||
(
|
||||
convIdentity(fromTypeArgument, toTypeArgument) and
|
||||
v = TNone()
|
||||
or
|
||||
convRefTypeTypeArgumentOut(fromTypeArgument, toTypeArgument, j) and
|
||||
convRefTypeTypeArgumentOut(fromTypeArgument, toTypeArgument, i) and
|
||||
v = TOut()
|
||||
or
|
||||
convRefTypeTypeArgumentIn(toTypeArgument, fromTypeArgument, j) and
|
||||
convRefTypeTypeArgumentIn(toTypeArgument, fromTypeArgument, i) and
|
||||
v = TIn()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -343,10 +343,10 @@ final class AssignmentNode extends ControlFlowElementNode {
|
||||
result.(TypeMentionNode).getTarget() = controlFlowElement
|
||||
or
|
||||
childIndex = 0 and
|
||||
result.(ElementNode).getElement() = assignment.getLValue()
|
||||
result.(ElementNode).getElement() = assignment.getLeftOperand()
|
||||
or
|
||||
childIndex = 1 and
|
||||
result.(ElementNode).getElement() = assignment.getRValue()
|
||||
result.(ElementNode).getElement() = assignment.getRightOperand()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -535,8 +535,8 @@ class Setter extends Accessor, @setter {
|
||||
exists(AssignExpr assign |
|
||||
this.getStatementBody().getNumberOfStmts() = 1 and
|
||||
assign.getParent() = this.getStatementBody().getAChild() and
|
||||
assign.getLValue() = result.getAnAccess() and
|
||||
assign.getRValue() = accessToValue()
|
||||
assign.getLeftOperand() = result.getAnAccess() and
|
||||
assign.getRightOperand() = accessToValue()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ private newtype TComparisonTest =
|
||||
compare.getComparisonKind().isCompare() and
|
||||
outerKind = outer.getComparisonKind() and
|
||||
outer.getAnArgument() = compare.getExpr() and
|
||||
i = outer.getAnArgument().getValue().toInt()
|
||||
i = outer.getAnArgument().getIntValue()
|
||||
|
|
||||
outerKind.isEquality() and
|
||||
(
|
||||
|
||||
@@ -32,13 +32,13 @@ private module ConstantComparisonOperation {
|
||||
|
||||
private int maxValue(Expr expr) {
|
||||
if convertedType(expr) instanceof IntegralType and exists(expr.getValue())
|
||||
then result = expr.getValue().toInt()
|
||||
then result = expr.getIntValue()
|
||||
else result = convertedType(expr).maxValue()
|
||||
}
|
||||
|
||||
private int minValue(Expr expr) {
|
||||
if convertedType(expr) instanceof IntegralType and exists(expr.getValue())
|
||||
then result = expr.getValue().toInt()
|
||||
then result = expr.getIntValue()
|
||||
else result = convertedType(expr).minValue()
|
||||
}
|
||||
|
||||
|
||||
@@ -60,25 +60,16 @@ private module GuardsInput implements
|
||||
override boolean asBooleanValue() { boolConst(this, result) }
|
||||
}
|
||||
|
||||
private predicate intConst(Expr e, int i) {
|
||||
e.getValue().toInt() = i and
|
||||
(
|
||||
e.getType() instanceof Enum
|
||||
or
|
||||
e.getType() instanceof IntegralType
|
||||
)
|
||||
}
|
||||
|
||||
private class IntegerConstant extends ConstantExpr {
|
||||
IntegerConstant() { intConst(this, _) }
|
||||
IntegerConstant() { exists(this.getIntValue()) }
|
||||
|
||||
override int asIntegerValue() { intConst(this, result) }
|
||||
override int asIntegerValue() { result = this.getIntValue() }
|
||||
}
|
||||
|
||||
private class EnumConst extends ConstantExpr {
|
||||
EnumConst() { this.getType() instanceof Enum and this.hasValue() }
|
||||
|
||||
override int asIntegerValue() { result = this.getValue().toInt() }
|
||||
override int asIntegerValue() { result = this.getIntValue() }
|
||||
}
|
||||
|
||||
private class StringConstant extends ConstantExpr instanceof StringLiteral {
|
||||
@@ -136,7 +127,7 @@ private module GuardsInput implements
|
||||
IdExpr() { this instanceof AssignExpr or this instanceof CastExpr }
|
||||
|
||||
Expr getEqualChildExpr() {
|
||||
result = this.(AssignExpr).getRValue()
|
||||
result = this.(AssignExpr).getRightOperand()
|
||||
or
|
||||
result = this.(CastExpr).getExpr()
|
||||
}
|
||||
@@ -517,35 +508,35 @@ class EnumerableCollectionExpr extends Expr {
|
||||
|
|
||||
// x.Length == 0
|
||||
ct.getComparisonKind().isEquality() and
|
||||
ct.getAnArgument().getValue().toInt() = 0 and
|
||||
ct.getAnArgument().getIntValue() = 0 and
|
||||
branch = isEmpty
|
||||
or
|
||||
// x.Length == k, k > 0
|
||||
ct.getComparisonKind().isEquality() and
|
||||
ct.getAnArgument().getValue().toInt() > 0 and
|
||||
ct.getAnArgument().getIntValue() > 0 and
|
||||
branch = true and
|
||||
isEmpty = false
|
||||
or
|
||||
// x.Length != 0
|
||||
ct.getComparisonKind().isInequality() and
|
||||
ct.getAnArgument().getValue().toInt() = 0 and
|
||||
ct.getAnArgument().getIntValue() = 0 and
|
||||
branch = isEmpty.booleanNot()
|
||||
or
|
||||
// x.Length != k, k != 0
|
||||
ct.getComparisonKind().isInequality() and
|
||||
ct.getAnArgument().getValue().toInt() != 0 and
|
||||
ct.getAnArgument().getIntValue() != 0 and
|
||||
branch = false and
|
||||
isEmpty = false
|
||||
or
|
||||
// x.Length > k, k >= 0
|
||||
ct.getComparisonKind().isLessThan() and
|
||||
ct.getFirstArgument().getValue().toInt() >= 0 and
|
||||
ct.getFirstArgument().getIntValue() >= 0 and
|
||||
branch = true and
|
||||
isEmpty = false
|
||||
or
|
||||
// x.Length >= k, k > 0
|
||||
ct.getComparisonKind().isLessThanEquals() and
|
||||
ct.getFirstArgument().getValue().toInt() > 0 and
|
||||
ct.getFirstArgument().getIntValue() > 0 and
|
||||
branch = true and
|
||||
isEmpty = false
|
||||
)
|
||||
@@ -836,7 +827,7 @@ module Internal {
|
||||
|
||||
/** Holds if expression `e2` is a `null` value whenever `e1` is. */
|
||||
predicate nullValueImpliedUnary(Expr e1, Expr e2) {
|
||||
e1 = e2.(AssignExpr).getRValue()
|
||||
e1 = e2.(AssignExpr).getRightOperand()
|
||||
or
|
||||
e1 = e2.(Cast).getExpr()
|
||||
or
|
||||
@@ -923,7 +914,7 @@ module Internal {
|
||||
/** Holds if expression `e2` is a non-`null` value whenever `e1` is. */
|
||||
predicate nonNullValueImpliedUnary(Expr e1, Expr e2) {
|
||||
e1 = e2.(CastExpr).getExpr() or
|
||||
e1 = e2.(AssignExpr).getRValue() or
|
||||
e1 = e2.(AssignExpr).getRightOperand() or
|
||||
e1 = e2.(NullCoalescingOperation).getAnOperand()
|
||||
}
|
||||
|
||||
|
||||
@@ -521,7 +521,7 @@ module Expressions {
|
||||
// ```
|
||||
// need special treatment, because the accesses `[0]`, `[1]`, and `[2]`
|
||||
// have no qualifier.
|
||||
this = any(MemberInitializer mi).getLValue()
|
||||
this = any(MemberInitializer mi).getLeftOperand()
|
||||
) and
|
||||
not exists(AssignableDefinitions::OutRefDefinition def | def.getTargetAccess() = this)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ private Expr maybeNullExpr(Expr reason) {
|
||||
or
|
||||
result instanceof AsExpr and reason = result
|
||||
or
|
||||
result.(AssignExpr).getRValue() = maybeNullExpr(reason)
|
||||
result.(AssignExpr).getRightOperand() = maybeNullExpr(reason)
|
||||
or
|
||||
result.(CastExpr).getExpr() = maybeNullExpr(reason)
|
||||
or
|
||||
|
||||
@@ -29,4 +29,8 @@ module CsharpDataFlow implements InputSig<Location> {
|
||||
predicate neverSkipInPathGraph(Node n) {
|
||||
exists(n.(AssignableDefinitionNode).getDefinition().getTargetAccess())
|
||||
}
|
||||
|
||||
DataFlowType getSourceContextParameterNodeType(Node p) {
|
||||
exists(p) and result.isSourceContextParameterType()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,7 +528,7 @@ module LocalFlow {
|
||||
e2 =
|
||||
any(AssignExpr ae |
|
||||
ae.getParent() = any(ControlFlowElement cfe | not cfe instanceof ExprStmt) and
|
||||
e1 = ae.getRValue()
|
||||
e1 = ae.getRightOperand()
|
||||
)
|
||||
or
|
||||
e1 = e2.(ObjectCreation).getInitializer()
|
||||
@@ -554,7 +554,7 @@ module LocalFlow {
|
||||
e2 = we
|
||||
)
|
||||
or
|
||||
exists(AssignExpr ae | ae.getLValue().(TupleExpr) = e2 and ae.getRValue() = e1)
|
||||
exists(AssignExpr ae | ae.getLeftOperand().(TupleExpr) = e2 and ae.getRightOperand() = e1)
|
||||
or
|
||||
exists(ControlFlowElement cfe | cfe = e2.(TupleExpr).(PatternExpr).getPatternMatch() |
|
||||
cfe.(IsExpr).getExpr() = e1
|
||||
@@ -795,7 +795,7 @@ private predicate fieldOrPropertyStore(ContentSet c, Expr src, Expr q, boolean p
|
||||
q = we and
|
||||
mi = we.getInitializer().getAMemberInitializer() and
|
||||
f = mi.getInitializedMember() and
|
||||
src = mi.getRValue() and
|
||||
src = mi.getRightOperand() and
|
||||
postUpdate = false
|
||||
)
|
||||
or
|
||||
@@ -804,7 +804,7 @@ private predicate fieldOrPropertyStore(ContentSet c, Expr src, Expr q, boolean p
|
||||
mi = q.(ObjectInitializer).getAMemberInitializer() and
|
||||
q.getParent() instanceof ObjectCreation and
|
||||
f = mi.getInitializedMember() and
|
||||
src = mi.getRValue() and
|
||||
src = mi.getRightOperand() and
|
||||
postUpdate = false
|
||||
)
|
||||
or
|
||||
@@ -879,8 +879,8 @@ private predicate arrayStore(Expr src, Expr a, boolean postUpdate) {
|
||||
// Member initializer, `new C { Array = { [i] = src } }`
|
||||
exists(MemberInitializer mi |
|
||||
mi = a.(ObjectInitializer).getAMemberInitializer() and
|
||||
mi.getLValue() instanceof ArrayAccess and
|
||||
mi.getRValue() = src and
|
||||
mi.getLeftOperand() instanceof ArrayAccess and
|
||||
mi.getRightOperand() = src and
|
||||
postUpdate = false
|
||||
)
|
||||
}
|
||||
@@ -1179,7 +1179,8 @@ private module Cached {
|
||||
cached
|
||||
newtype TDataFlowType =
|
||||
TGvnDataFlowType(Gvn::GvnType t) or
|
||||
TDelegateDataFlowType(Callable lambda) { lambdaCreationExpr(_, lambda) }
|
||||
TDelegateDataFlowType(Callable lambda) { lambdaCreationExpr(_, lambda) } or
|
||||
TSourceContextParameterType()
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -2394,6 +2395,8 @@ class DataFlowType extends TDataFlowType {
|
||||
|
||||
Callable asDelegate() { this = TDelegateDataFlowType(result) }
|
||||
|
||||
predicate isSourceContextParameterType() { this = TSourceContextParameterType() }
|
||||
|
||||
/**
|
||||
* Gets an expression that creates a delegate of this type.
|
||||
*
|
||||
@@ -2412,6 +2415,9 @@ class DataFlowType extends TDataFlowType {
|
||||
result = this.asGvnType().toString()
|
||||
or
|
||||
result = this.asDelegate().toString()
|
||||
or
|
||||
this.isSourceContextParameterType() and
|
||||
result = "<source context parameter type>"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2469,6 +2475,11 @@ private predicate compatibleTypesDelegateLeft(DataFlowType dt1, DataFlowType dt2
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate compatibleTypesSourceContextParameterTypeLeft(DataFlowType dt1, DataFlowType dt2) {
|
||||
dt1.isSourceContextParameterType() and not exists(dt2.asDelegate())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
@@ -2499,6 +2510,10 @@ predicate compatibleTypes(DataFlowType dt1, DataFlowType dt2) {
|
||||
compatibleTypesDelegateLeft(dt2, dt1)
|
||||
or
|
||||
dt1.asDelegate() = dt2.asDelegate()
|
||||
or
|
||||
compatibleTypesSourceContextParameterTypeLeft(dt1, dt2)
|
||||
or
|
||||
compatibleTypesSourceContextParameterTypeLeft(dt2, dt1)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2511,6 +2526,8 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
||||
uselessTypebound(t2)
|
||||
or
|
||||
compatibleTypesDelegateLeft(t1, t2)
|
||||
or
|
||||
compatibleTypesSourceContextParameterTypeLeft(t1, t2)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2582,7 +2599,7 @@ module PostUpdateNodes {
|
||||
call.getExpr() = init.(CollectionInitializer).getAnElementInitializer()
|
||||
or
|
||||
// E.g. `new Dictionary<int, string>() { [0] = "a", [1] = "b" }`
|
||||
call.getExpr() = init.(ObjectInitializer).getAMemberInitializer().getLValue()
|
||||
call.getExpr() = init.(ObjectInitializer).getAMemberInitializer().getLeftOperand()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2795,7 +2812,7 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
|
||||
preservesValue = true
|
||||
or
|
||||
exists(AddEventExpr aee |
|
||||
nodeFrom.asExpr() = aee.getRValue() and
|
||||
nodeFrom.asExpr() = aee.getRightOperand() and
|
||||
nodeTo.asExpr().(EventRead).getTarget() = aee.getTarget() and
|
||||
preservesValue = false
|
||||
)
|
||||
|
||||
@@ -4,13 +4,17 @@
|
||||
* Provides classes and predicates for dealing with MaD flow models specified
|
||||
* in data extensions and CSV format.
|
||||
*
|
||||
* The CSV specification has the following columns:
|
||||
* The extensible relations have the following columns:
|
||||
* - Sources:
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
|
||||
* - Sinks:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; kind; provenance`
|
||||
* - Summaries:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance`
|
||||
* - Barriers:
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
|
||||
* - BarrierGuards:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; acceptingValue; kind; provenance`
|
||||
* - Neutrals:
|
||||
* `namespace; type; name; signature; kind; provenance`
|
||||
* A neutral is used to indicate that a callable is neutral with respect to flow (no summary), source (is not a source) or sink (is not a sink).
|
||||
@@ -69,14 +73,17 @@
|
||||
* - "Field[f]": Selects the contents of field `f`.
|
||||
* - "Property[p]": Selects the contents of property `p`.
|
||||
*
|
||||
* 8. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* 8. The `acceptingValue` column of barrier guard models specifies the condition
|
||||
* under which the guard blocks flow. It can be one of "true" or "false". In
|
||||
* the future "no-exception", "not-zero", "null", "not-null" may be supported.
|
||||
* 9. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* which classes the interpreted elements should be added. For example, for
|
||||
* sources "remote" indicates a default remote flow source, and for summaries
|
||||
* "taint" indicates a default additional taint step and "value" indicates a
|
||||
* globally applicable value-preserving step. For neutrals the kind can be `summary`,
|
||||
* `source` or `sink` to indicate that the neutral is neutral with respect to
|
||||
* flow (no summary), source (is not a source) or sink (is not a sink).
|
||||
* 9. The `provenance` column is a tag to indicate the origin and verification of a model.
|
||||
* 10. The `provenance` column is a tag to indicate the origin and verification of a model.
|
||||
* The format is {origin}-{verification} or just "manual" where the origin describes
|
||||
* the origin of the model and verification describes how the model has been verified.
|
||||
* Some examples are:
|
||||
@@ -230,11 +237,11 @@ module ModelValidation {
|
||||
result = "Unrecognized provenance description \"" + provenance + "\" in " + pred + " model."
|
||||
)
|
||||
or
|
||||
exists(string acceptingvalue |
|
||||
barrierGuardModel(_, _, _, _, _, _, _, acceptingvalue, _, _, _) and
|
||||
invalidAcceptingValue(acceptingvalue) and
|
||||
exists(string acceptingValue |
|
||||
barrierGuardModel(_, _, _, _, _, _, _, acceptingValue, _, _, _) and
|
||||
invalidAcceptingValue(acceptingValue) and
|
||||
result =
|
||||
"Unrecognized accepting value description \"" + acceptingvalue +
|
||||
"Unrecognized accepting value description \"" + acceptingValue +
|
||||
"\" in barrier guard model."
|
||||
)
|
||||
}
|
||||
@@ -482,13 +489,13 @@ private module Cached {
|
||||
|
||||
private predicate barrierGuardChecks(Guard g, Expr e, GuardValue gv, TKindModelPair kmp) {
|
||||
exists(
|
||||
SourceSinkInterpretationInput::InterpretNode n, AcceptingValue acceptingvalue, string kind,
|
||||
SourceSinkInterpretationInput::InterpretNode n, AcceptingValue acceptingValue, string kind,
|
||||
string model
|
||||
|
|
||||
isBarrierGuardNode(n, acceptingvalue, kind, model) and
|
||||
isBarrierGuardNode(n, acceptingValue, kind, model) and
|
||||
n.asNode().asExpr() = e and
|
||||
kmp = TMkPair(kind, model) and
|
||||
gv = convertAcceptingValue(acceptingvalue)
|
||||
gv = convertAcceptingValue(acceptingValue)
|
||||
|
|
||||
g.(Call).getAnArgument() = e or g.(QualifiableExpr).getQualifier() = e
|
||||
)
|
||||
|
||||
@@ -33,7 +33,7 @@ extensible predicate barrierModel(
|
||||
*/
|
||||
extensible predicate barrierGuardModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string acceptingvalue, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
string input, string acceptingValue, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -253,13 +253,13 @@ module SourceSinkInterpretationInput implements
|
||||
}
|
||||
|
||||
predicate barrierGuardElement(
|
||||
Element e, string input, Public::AcceptingValue acceptingvalue, string kind,
|
||||
Element e, string input, Public::AcceptingValue acceptingValue, string kind,
|
||||
Public::Provenance provenance, string model
|
||||
) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
barrierGuardModel(namespace, type, subtypes, name, signature, ext, input, acceptingvalue,
|
||||
barrierGuardModel(namespace, type, subtypes, name, signature, ext, input, acceptingValue,
|
||||
kind, provenance, model) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext, _)
|
||||
)
|
||||
|
||||
@@ -337,7 +337,7 @@ private module CallGraph {
|
||||
pred = succ.(DelegateCreation).getArgument()
|
||||
or
|
||||
exists(AddEventExpr ae | succ.(EventAccess).getTarget() = ae.getTarget() |
|
||||
pred = ae.getRValue()
|
||||
pred = ae.getRightOperand()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ predicate systemArrayLengthAccess(PropertyAccess pa) {
|
||||
* - a read of the `Length` of an array with `val` lengths.
|
||||
*/
|
||||
private predicate constantIntegerExpr(ExprNode e, int val) {
|
||||
e.getValue().toInt() = val
|
||||
e.getExpr().getIntValue() = val
|
||||
or
|
||||
exists(ExprNode src |
|
||||
e = getAnExplicitDefinitionRead(src) and
|
||||
|
||||
@@ -21,7 +21,7 @@ private module Impl {
|
||||
/** Holds if SSA definition `def` equals `e + delta`. */
|
||||
predicate ssaUpdateStep(ExplicitDefinition def, ExprNode e, int delta) {
|
||||
exists(ControlFlow::Node cfn | cfn = def.getControlFlowNode() |
|
||||
e = cfn.(ExprNode::Assignment).getRValue() and
|
||||
e = cfn.(ExprNode::Assignment).getRightOperand() and
|
||||
delta = 0 and
|
||||
not cfn instanceof ExprNode::AssignOperation
|
||||
or
|
||||
@@ -39,7 +39,7 @@ private module Impl {
|
||||
|
||||
/** Holds if `e1 + delta` equals `e2`. */
|
||||
predicate valueFlowStep(ExprNode e2, ExprNode e1, int delta) {
|
||||
e2.(ExprNode::AssignExpr).getRValue() = e1 and delta = 0
|
||||
e2.(ExprNode::AssignExpr).getRightOperand() = e1 and delta = 0
|
||||
or
|
||||
e2.(ExprNode::UnaryPlusExpr).getOperand() = e1 and delta = 0
|
||||
or
|
||||
@@ -207,13 +207,13 @@ module ExprNode {
|
||||
override CS::Assignment e;
|
||||
|
||||
/** Gets the left operand of this assignment. */
|
||||
ExprNode getLValue() {
|
||||
result = unique(ExprNode res | hasChild(e, e.getLValue(), this, res) | res)
|
||||
ExprNode getLeftOperand() {
|
||||
result = unique(ExprNode res | hasChild(e, e.getLeftOperand(), this, res) | res)
|
||||
}
|
||||
|
||||
/** Gets the right operand of this assignment. */
|
||||
ExprNode getRValue() {
|
||||
result = unique(ExprNode res | hasChild(e, e.getRValue(), this, res) | res)
|
||||
ExprNode getRightOperand() {
|
||||
result = unique(ExprNode res | hasChild(e, e.getRightOperand(), this, res) | res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,6 +225,10 @@ module ExprNode {
|
||||
/** A compound assignment operation. */
|
||||
class AssignOperation extends Assignment, BinaryOperation {
|
||||
override CS::AssignOperation e;
|
||||
|
||||
override ExprNode getLeftOperand() { result = Assignment.super.getLeftOperand() }
|
||||
|
||||
override ExprNode getRightOperand() { result = Assignment.super.getRightOperand() }
|
||||
}
|
||||
|
||||
/** A unary operation. */
|
||||
|
||||
@@ -168,7 +168,7 @@ private module Impl {
|
||||
/** Returned an expression that is assigned to `f`. */
|
||||
ExprNode getAssignedValueToField(Field f) {
|
||||
result.getExpr() in [
|
||||
f.getAnAssignedValue(), any(AssignOperation a | a.getLValue() = f.getAnAccess())
|
||||
f.getAnAssignedValue(), any(AssignOperation a | a.getLeftOperand() = f.getAnAccess())
|
||||
]
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ private module Impl {
|
||||
/** Returns a sub expression of `e` for expression types where the sign depends on the child. */
|
||||
ExprNode getASubExprWithSameSign(ExprNode e) {
|
||||
exists(Expr e_, Expr child | hasChild(e_, child, e, result) |
|
||||
child = e_.(AssignExpr).getRValue() or
|
||||
child = e_.(AssignExpr).getRightOperand() or
|
||||
child = e_.(UnaryPlusExpr).getOperand() or
|
||||
child = e_.(PostIncrExpr).getOperand() or
|
||||
child = e_.(PostDecrExpr).getOperand() or
|
||||
|
||||
@@ -55,5 +55,5 @@ ExprNode ssaRead(Definition v, int delta) {
|
||||
or
|
||||
v.(ExplicitDefinition).getControlFlowNode().(ExprNode::Assignment) = result and delta = 0
|
||||
or
|
||||
result.(ExprNode::AssignExpr).getRValue() = ssaRead(v, delta)
|
||||
result.(ExprNode::AssignExpr).getRightOperand() = ssaRead(v, delta)
|
||||
}
|
||||
|
||||
@@ -1348,7 +1348,7 @@ private module Internal {
|
||||
any(DynamicMemberAccess dma | this = TDispatchDynamicEventAccess(_, dma, _)).getQualifier()
|
||||
}
|
||||
|
||||
override Expr getArgument(int i) { i = 0 and result = this.getCall().getRValue() }
|
||||
override Expr getArgument(int i) { i = 0 and result = this.getCall().getRightOperand() }
|
||||
}
|
||||
|
||||
/** A call to a constructor using dynamic types. */
|
||||
|
||||
@@ -112,7 +112,7 @@ class BaseAccess extends Access, @base_access_expr {
|
||||
class MemberAccess extends Access, QualifiableExpr, @member_access_expr {
|
||||
override predicate hasImplicitThisQualifier() {
|
||||
QualifiableExpr.super.hasImplicitThisQualifier() and
|
||||
not exists(MemberInitializer mi | mi.getLValue() = this)
|
||||
not exists(MemberInitializer mi | mi.getLeftOperand() = this)
|
||||
}
|
||||
|
||||
override Member getQualifiedDeclaration() { result = this.getTarget() }
|
||||
|
||||
@@ -20,14 +20,22 @@ class Assignment extends BinaryOperation, @assign_expr {
|
||||
expr_parent(_, 1, this)
|
||||
}
|
||||
|
||||
/** Gets the left operand of this assignment. */
|
||||
Expr getLValue() { result = this.getLeftOperand() }
|
||||
/**
|
||||
* DEPRECATED: Use `getLeftOperand` instead.
|
||||
*
|
||||
* Gets the left operand of this assignment.
|
||||
*/
|
||||
deprecated Expr getLValue() { result = this.getLeftOperand() }
|
||||
|
||||
/** Gets the right operand of this assignment. */
|
||||
Expr getRValue() { result = this.getRightOperand() }
|
||||
/**
|
||||
* DEPRECATED: Use `getRightOperand` instead.
|
||||
*
|
||||
* Gets the right operand of this assignment.
|
||||
*/
|
||||
deprecated Expr getRValue() { result = this.getRightOperand() }
|
||||
|
||||
/** Gets the variable being assigned to, if any. */
|
||||
Variable getTargetVariable() { result.getAnAccess() = this.getLValue() }
|
||||
Variable getTargetVariable() { result.getAnAccess() = this.getLeftOperand() }
|
||||
|
||||
override string getOperator() { none() }
|
||||
}
|
||||
@@ -40,7 +48,12 @@ class LocalVariableDeclAndInitExpr extends LocalVariableDeclExpr, Assignment {
|
||||
|
||||
override LocalVariable getTargetVariable() { result = this.getVariable() }
|
||||
|
||||
override LocalVariableAccess getLValue() { result = Assignment.super.getLValue() }
|
||||
/**
|
||||
* DEPRECATED: Use `getLeftOperand` instead.
|
||||
*/
|
||||
deprecated override LocalVariableAccess getLValue() { result = this.getLeftOperand() }
|
||||
|
||||
override LocalVariableAccess getLeftOperand() { result = Assignment.super.getLeftOperand() }
|
||||
|
||||
override string toString() { result = LocalVariableDeclExpr.super.toString() + " = ..." }
|
||||
|
||||
@@ -223,9 +236,12 @@ deprecated class AssignUnsighedRightShiftExpr = AssignUnsignedRightShiftExpr;
|
||||
*/
|
||||
class AddOrRemoveEventExpr extends AssignOperation, @assign_event_expr {
|
||||
/** Gets the event targeted by this event assignment. */
|
||||
Event getTarget() { result = this.getLValue().getTarget() }
|
||||
Event getTarget() { result = this.getLeftOperand().getTarget() }
|
||||
|
||||
override EventAccess getLValue() { result = this.getChild(0) }
|
||||
/**
|
||||
* DEPRECATED: Use `getLeftOperand` instead.
|
||||
*/
|
||||
deprecated override EventAccess getLValue() { result = this.getLeftOperand() }
|
||||
|
||||
override EventAccess getLeftOperand() { result = this.getChild(0) }
|
||||
}
|
||||
|
||||
@@ -773,7 +773,7 @@ class EventCall extends AccessorCall, EventAccessExpr {
|
||||
override EventAccessor getTarget() {
|
||||
exists(Event e, AddOrRemoveEventExpr aoree |
|
||||
e = this.getEvent() and
|
||||
aoree.getLValue() = this
|
||||
aoree.getLeftOperand() = this
|
||||
|
|
||||
aoree instanceof AddEventExpr and result = e.getAddEventAccessor()
|
||||
or
|
||||
@@ -784,8 +784,8 @@ class EventCall extends AccessorCall, EventAccessExpr {
|
||||
override Expr getArgument(int i) {
|
||||
i = 0 and
|
||||
exists(AddOrRemoveEventExpr aoree |
|
||||
aoree.getLValue() = this and
|
||||
result = aoree.getRValue()
|
||||
aoree.getLeftOperand() = this and
|
||||
result = aoree.getRightOperand()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ class MemberInitializer extends AssignExpr {
|
||||
MemberInitializer() { this.getParent() instanceof ObjectInitializer }
|
||||
|
||||
/** Gets the initialized member. */
|
||||
Member getInitializedMember() { result.getAnAccess() = this.getLValue() }
|
||||
Member getInitializedMember() { result.getAnAccess() = this.getLeftOperand() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MemberInitializer" }
|
||||
}
|
||||
|
||||
@@ -57,6 +57,13 @@ class Expr extends ControlFlowElement, @expr {
|
||||
/** Gets the value of this expression, if any */
|
||||
string getValue() { expr_value(this, result) }
|
||||
|
||||
/** Gets the integer value of this expression, if any. */
|
||||
cached
|
||||
int getIntValue() {
|
||||
result = this.getValue().toInt() and
|
||||
(this.getType() instanceof IntegralType or this.getType() instanceof Enum)
|
||||
}
|
||||
|
||||
/** Holds if this expression has a value. */
|
||||
final predicate hasValue() { exists(this.getValue()) }
|
||||
|
||||
@@ -1099,7 +1106,7 @@ class QualifiableExpr extends Expr, @qualifiable_expr {
|
||||
}
|
||||
|
||||
private Expr getAnAssignOrForeachChild() {
|
||||
result = any(AssignExpr e).getLValue()
|
||||
result = any(AssignExpr e).getLeftOperand()
|
||||
or
|
||||
result = any(ForeachStmt fs).getVariableDeclTuple()
|
||||
or
|
||||
|
||||
@@ -41,6 +41,6 @@ class ReturnedByMockObject extends ObjectCreation {
|
||||
* Gets a value used to initialize a member of this object creation.
|
||||
*/
|
||||
Expr getAMemberInitializationValue() {
|
||||
result = this.getInitializer().(ObjectInitializer).getAMemberInitializer().getRValue()
|
||||
result = this.getInitializer().(ObjectInitializer).getAMemberInitializer().getRightOperand()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ abstract class SqlExpr extends Expr {
|
||||
class CommandTextAssignmentSqlExpr extends SqlExpr, AssignExpr {
|
||||
CommandTextAssignmentSqlExpr() {
|
||||
exists(Property p, SystemDataIDbCommandInterface i, Property text |
|
||||
p = this.getLValue().(PropertyAccess).getTarget() and
|
||||
p = this.getLeftOperand().(PropertyAccess).getTarget() and
|
||||
text = i.getCommandTextProperty()
|
||||
|
|
||||
p.overridesOrImplementsOrEquals(text)
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getSql() { result = this.getRValue() }
|
||||
override Expr getSql() { result = this.getRightOperand() }
|
||||
}
|
||||
|
||||
/** A construction of an unknown `IDbCommand` object. */
|
||||
|
||||
@@ -81,7 +81,7 @@ class SystemRuntimeCompilerServicesInlineArrayAttribute extends Attribute {
|
||||
/**
|
||||
* Gets the length of the inline array.
|
||||
*/
|
||||
int getLength() { result = this.getConstructorArgument(0).getValue().toInt() }
|
||||
int getLength() { result = this.getConstructorArgument(0).getIntValue() }
|
||||
}
|
||||
|
||||
/** An attribute of type `System.Runtime.CompilerServices.OverloadResolutionPriority`. */
|
||||
@@ -94,5 +94,5 @@ class SystemRuntimeCompilerServicesOverloadResolutionPriorityAttribute extends A
|
||||
/**
|
||||
* Gets the priority number.
|
||||
*/
|
||||
int getPriority() { result = this.getConstructorArgument(0).getValue().toInt() }
|
||||
int getPriority() { result = this.getConstructorArgument(0).getIntValue() }
|
||||
}
|
||||
|
||||
@@ -100,20 +100,20 @@ Expr getAValueForCookiePolicyProp(string prop) {
|
||||
Expr getAValueForProp(ObjectCreation create, Assignment a, string prop) {
|
||||
// values set in object init
|
||||
exists(MemberInitializer init, Expr src, PropertyAccess pa |
|
||||
a.getLValue() = pa and
|
||||
a.getLeftOperand() = pa and
|
||||
pa.getTarget().hasName(prop) and
|
||||
init = create.getInitializer().(ObjectInitializer).getAMemberInitializer() and
|
||||
init.getLValue() = pa and
|
||||
DataFlow::localExprFlow(src, init.getRValue()) and
|
||||
init.getLeftOperand() = pa and
|
||||
DataFlow::localExprFlow(src, init.getRightOperand()) and
|
||||
result = src
|
||||
)
|
||||
or
|
||||
// values set on var that create is assigned to
|
||||
exists(Expr src, PropertyAccess pa |
|
||||
a.getLValue() = pa and
|
||||
a.getLeftOperand() = pa and
|
||||
pa.getTarget().hasName(prop) and
|
||||
DataFlow::localExprFlow(create, pa.getQualifier()) and
|
||||
DataFlow::localExprFlow(src, a.getRValue()) and
|
||||
DataFlow::localExprFlow(src, a.getRightOperand()) and
|
||||
result = src
|
||||
)
|
||||
}
|
||||
@@ -138,15 +138,15 @@ private module OnAppendCookieTrackingConfig<propertyName/0 getPropertyName> impl
|
||||
exists(PropertyWrite pw, Assignment delegateAssign, Callable c |
|
||||
pw.getProperty().getName() = "OnAppendCookie" and
|
||||
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreBuilderCookiePolicyOptions and
|
||||
delegateAssign.getLValue() = pw and
|
||||
delegateAssign.getLeftOperand() = pw and
|
||||
(
|
||||
exists(LambdaExpr lambda |
|
||||
delegateAssign.getRValue() = lambda and
|
||||
delegateAssign.getRightOperand() = lambda and
|
||||
lambda = c
|
||||
)
|
||||
or
|
||||
exists(DelegateCreation delegate |
|
||||
delegateAssign.getRValue() = delegate and
|
||||
delegateAssign.getRightOperand() = delegate and
|
||||
delegate.getArgument().(CallableAccess).getTarget() = c
|
||||
)
|
||||
) and
|
||||
@@ -159,9 +159,9 @@ private module OnAppendCookieTrackingConfig<propertyName/0 getPropertyName> impl
|
||||
exists(PropertyWrite pw, Assignment a |
|
||||
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||
pw.getProperty().getName() = getPropertyName() and
|
||||
a.getLValue() = pw and
|
||||
a.getLeftOperand() = pw and
|
||||
exists(Expr val |
|
||||
DataFlow::localExprFlow(val, a.getRValue()) and
|
||||
DataFlow::localExprFlow(val, a.getRightOperand()) and
|
||||
val.getValue() = "true"
|
||||
) and
|
||||
sink.asExpr() = pw.getQualifier()
|
||||
|
||||
@@ -126,16 +126,16 @@ private module TypeNameTrackingConfig implements DataFlow::ConfigSig {
|
||||
or
|
||||
node1.getType() instanceof TypeNameHandlingEnum and
|
||||
exists(PropertyWrite pw, Property p, Assignment a |
|
||||
a.getLValue() = pw and
|
||||
a.getLeftOperand() = pw and
|
||||
pw.getProperty() = p and
|
||||
p.getDeclaringType() instanceof JsonSerializerSettingsClass and
|
||||
p.hasName("TypeNameHandling") and
|
||||
(
|
||||
node1.asExpr() = a.getRValue() and
|
||||
node1.asExpr() = a.getRightOperand() and
|
||||
node2.asExpr() = pw.getQualifier()
|
||||
or
|
||||
exists(ObjectInitializer oi |
|
||||
node1.asExpr() = oi.getAMemberInitializer().getRValue() and
|
||||
node1.asExpr() = oi.getAMemberInitializer().getRightOperand() and
|
||||
node2.asExpr() = oi
|
||||
)
|
||||
)
|
||||
|
||||
@@ -84,15 +84,15 @@ private Expr getAValueForProp(ObjectCreation create, string prop) {
|
||||
// values set in object init
|
||||
exists(MemberInitializer init |
|
||||
init = create.getInitializer().(ObjectInitializer).getAMemberInitializer() and
|
||||
init.getLValue().(PropertyAccess).getTarget().hasName(prop) and
|
||||
result = init.getRValue()
|
||||
init.getLeftOperand().(PropertyAccess).getTarget().hasName(prop) and
|
||||
result = init.getRightOperand()
|
||||
)
|
||||
or
|
||||
// values set on var that create is assigned to
|
||||
exists(Assignment propAssign |
|
||||
DataFlow::localExprFlow(create, propAssign.getLValue().(PropertyAccess).getQualifier()) and
|
||||
propAssign.getLValue().(PropertyAccess).getTarget().hasName(prop) and
|
||||
result = propAssign.getRValue()
|
||||
DataFlow::localExprFlow(create, propAssign.getLeftOperand().(PropertyAccess).getQualifier()) and
|
||||
propAssign.getLeftOperand().(PropertyAccess).getTarget().hasName(prop) and
|
||||
result = propAssign.getRightOperand()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -84,9 +84,9 @@ where
|
||||
not f.getDeclaringType() instanceof Enum and
|
||||
not f.getType() instanceof Struct and
|
||||
not exists(Assignment ae, Field g |
|
||||
ae.getLValue().(FieldAccess).getTarget() = g and
|
||||
ae.getLeftOperand().(FieldAccess).getTarget() = g and
|
||||
g.getUnboundDeclaration() = f and
|
||||
not ae.getRValue() instanceof NullLiteral
|
||||
not ae.getRightOperand() instanceof NullLiteral
|
||||
) and
|
||||
not exists(MethodCall mc, int i, Field g |
|
||||
exists(Parameter p | mc.getTarget().getParameter(i) = p | p.isOut() or p.isRef()) and
|
||||
@@ -101,7 +101,7 @@ where
|
||||
not init instanceof NullLiteral
|
||||
) and
|
||||
not exists(AssignOperation ua, Field g |
|
||||
ua.getLValue().(FieldAccess).getTarget() = g and
|
||||
ua.getLeftOperand().(FieldAccess).getTarget() = g and
|
||||
g.getUnboundDeclaration() = f
|
||||
) and
|
||||
not exists(MutatorOperation op |
|
||||
|
||||
@@ -60,16 +60,16 @@ module LambdaDataFlow {
|
||||
}
|
||||
|
||||
Element getAssignmentTarget(Expr e) {
|
||||
exists(Assignment a | a.getRValue() = e |
|
||||
result = a.getLValue().(PropertyAccess).getTarget() or
|
||||
result = a.getLValue().(FieldAccess).getTarget() or
|
||||
result = a.getLValue().(LocalVariableAccess).getTarget() or
|
||||
result = a.getLValue().(EventAccess).getTarget()
|
||||
exists(Assignment a | a.getRightOperand() = e |
|
||||
result = a.getLeftOperand().(PropertyAccess).getTarget() or
|
||||
result = a.getLeftOperand().(FieldAccess).getTarget() or
|
||||
result = a.getLeftOperand().(LocalVariableAccess).getTarget() or
|
||||
result = a.getLeftOperand().(EventAccess).getTarget()
|
||||
)
|
||||
or
|
||||
exists(AddEventExpr aee |
|
||||
e = aee.getRValue() and
|
||||
result = aee.getLValue().getTarget()
|
||||
e = aee.getRightOperand() and
|
||||
result = aee.getLeftOperand().getTarget()
|
||||
)
|
||||
or
|
||||
result = getCollectionAssignmentTarget(e)
|
||||
@@ -97,8 +97,8 @@ Element getCollectionAssignmentTarget(Expr e) {
|
||||
// Store values using indexer
|
||||
exists(IndexerAccess ia, AssignExpr ae |
|
||||
ia.getQualifier() = result.(Variable).getAnAccess() and
|
||||
ia = ae.getLValue() and
|
||||
e = ae.getRValue()
|
||||
ia = ae.getLeftOperand() and
|
||||
e = ae.getRightOperand()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import csharp
|
||||
import semmle.code.csharp.commons.StructuralComparison
|
||||
|
||||
private Expr getAssignedExpr(Stmt stmt) {
|
||||
result = stmt.stripSingletonBlocks().(ExprStmt).getExpr().(AssignExpr).getLValue()
|
||||
result = stmt.stripSingletonBlocks().(ExprStmt).getExpr().(AssignExpr).getLeftOperand()
|
||||
}
|
||||
|
||||
from IfStmt is, string what
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
import csharp
|
||||
|
||||
predicate isDefinitelyPositive(Expr e) {
|
||||
e.getValue().toInt() >= 0 or
|
||||
e.getIntValue() >= 0 or
|
||||
e.(PropertyAccess).getTarget().hasName("Length") or
|
||||
e.(MethodCall).getTarget().hasUndecoratedName("Count")
|
||||
}
|
||||
@@ -23,12 +23,12 @@ where
|
||||
t.getLeftOperand() = lhs and
|
||||
t.getRightOperand() = rhs and
|
||||
not isDefinitelyPositive(lhs.getLeftOperand().stripCasts()) and
|
||||
lhs.getRightOperand().(IntegerLiteral).getValue() = "2" and
|
||||
lhs.getRightOperand().(IntegerLiteral).getIntValue() = 2 and
|
||||
(
|
||||
t instanceof EQExpr and rhs.getValue() = "1" and parity = "oddness"
|
||||
t instanceof EQExpr and rhs.getIntValue() = 1 and parity = "oddness"
|
||||
or
|
||||
t instanceof NEExpr and rhs.getValue() = "1" and parity = "evenness"
|
||||
t instanceof NEExpr and rhs.getIntValue() = 1 and parity = "evenness"
|
||||
or
|
||||
t instanceof GTExpr and rhs.getValue() = "0" and parity = "oddness"
|
||||
t instanceof GTExpr and rhs.getIntValue() = 0 and parity = "oddness"
|
||||
)
|
||||
select t, "Possibly invalid test for " + parity + ". This will fail for negative numbers."
|
||||
|
||||
@@ -23,9 +23,10 @@ where
|
||||
) and
|
||||
forex(Access a | a = v.getAnAccess() |
|
||||
a = any(ModifierMethodCall m).getQualifier() or
|
||||
a = any(AssignExpr ass | ass.getRValue() instanceof ObjectCreation).getLValue() or
|
||||
a = any(AssignExpr ass | ass.getRightOperand() instanceof ObjectCreation).getLeftOperand() or
|
||||
a =
|
||||
any(LocalVariableDeclAndInitExpr ass | ass.getRValue() instanceof ObjectCreation).getLValue()
|
||||
any(LocalVariableDeclAndInitExpr ass | ass.getRightOperand() instanceof ObjectCreation)
|
||||
.getLeftOperand()
|
||||
) and
|
||||
not v = any(ForeachStmt fs).getVariable() and
|
||||
not v = any(BindingPatternExpr vpe).getVariableDeclExpr().getVariable() and
|
||||
|
||||
@@ -27,8 +27,8 @@ predicate isExactEraStartDateCreation(ObjectCreation cr) {
|
||||
cr.getType().hasFullyQualifiedName("System", "DateTime") or
|
||||
cr.getType().hasFullyQualifiedName("System", "DateTimeOffset")
|
||||
) and
|
||||
isEraStart(cr.getArgument(0).getValue().toInt(), cr.getArgument(1).getValue().toInt(),
|
||||
cr.getArgument(2).getValue().toInt())
|
||||
isEraStart(cr.getArgument(0).getIntValue(), cr.getArgument(1).getIntValue(),
|
||||
cr.getArgument(2).getIntValue())
|
||||
}
|
||||
|
||||
predicate isDateFromJapaneseCalendarToDateTime(MethodCall mc) {
|
||||
@@ -44,7 +44,7 @@ predicate isDateFromJapaneseCalendarToDateTime(MethodCall mc) {
|
||||
mc.getNumberOfArguments() = 7 // implicitly current era
|
||||
or
|
||||
mc.getNumberOfArguments() = 8 and
|
||||
mc.getArgument(7).getValue() = "0"
|
||||
mc.getArgument(7).getIntValue() = 0
|
||||
) // explicitly current era
|
||||
}
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ predicate convertedToFloatOrDecimal(Expr e, Type t) {
|
||||
/** Holds if `div` is an exact integer division. */
|
||||
predicate exactDivision(DivExpr div) {
|
||||
exists(int numerator, int denominator |
|
||||
numerator = div.getNumerator().stripCasts().getValue().toInt() and
|
||||
denominator = div.getDenominator().stripCasts().getValue().toInt() and
|
||||
numerator = div.getNumerator().stripCasts().getIntValue() and
|
||||
denominator = div.getDenominator().stripCasts().getIntValue() and
|
||||
numerator % denominator = 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ private predicate candidate(AssignExpr ae) {
|
||||
not ae instanceof MemberInitializer and
|
||||
// Enum field initializers are never self assignments. `enum E { A = 42 }`
|
||||
not ae.getParent().(Field).getDeclaringType() instanceof Enum and
|
||||
forall(Expr e | e = ae.getLValue().getAChildExpr*() |
|
||||
forall(Expr e | e = ae.getLeftOperand().getAChildExpr*() |
|
||||
// Non-trivial property accesses may have side-effects,
|
||||
// so these are not considered
|
||||
e instanceof PropertyAccess implies e instanceof TrivialPropertyAccess
|
||||
@@ -28,7 +28,7 @@ private predicate candidate(AssignExpr ae) {
|
||||
|
||||
private predicate selfAssignExpr(AssignExpr ae) {
|
||||
candidate(ae) and
|
||||
sameGvn(ae.getLValue(), ae.getRValue())
|
||||
sameGvn(ae.getLeftOperand(), ae.getRightOperand())
|
||||
}
|
||||
|
||||
private Declaration getDeclaration(Expr e) {
|
||||
@@ -40,5 +40,5 @@ private Declaration getDeclaration(Expr e) {
|
||||
}
|
||||
|
||||
from AssignExpr ae, Declaration target
|
||||
where selfAssignExpr(ae) and target = getDeclaration(ae.getLValue())
|
||||
where selfAssignExpr(ae) and target = getDeclaration(ae.getLeftOperand())
|
||||
select ae, "This assignment assigns $@ to itself.", target, target.getName()
|
||||
|
||||
@@ -50,7 +50,7 @@ predicate potentiallyConsumingAccess(VariableAccess va) {
|
||||
Expr sequenceSource(IEnumerableSequence seq) {
|
||||
result = seq.getInitializer()
|
||||
or
|
||||
exists(Assignment a | a.getLValue() = seq.getAnAccess() and result = a.getRValue())
|
||||
exists(Assignment a | a.getLeftOperand() = seq.getAnAccess() and result = a.getRightOperand())
|
||||
}
|
||||
|
||||
from IEnumerableSequence seq, VariableAccess va
|
||||
|
||||
@@ -24,7 +24,7 @@ class StringCat extends AddExpr {
|
||||
*/
|
||||
predicate isSelfConcatAssignExpr(AssignExpr e, Variable v) {
|
||||
exists(VariableAccess use |
|
||||
stringCatContains(e.getRValue(), use) and
|
||||
stringCatContains(e.getRightOperand(), use) and
|
||||
use.getTarget() = e.getTargetVariable() and
|
||||
v = use.getTarget()
|
||||
)
|
||||
@@ -41,7 +41,7 @@ predicate stringCatContains(StringCat expr, Expr child) {
|
||||
* where `v` is a simple variable (and not, for example, a property).
|
||||
*/
|
||||
predicate isConcatExpr(AssignAddExpr e, Variable v) {
|
||||
e.getLValue().getType() instanceof StringType and
|
||||
e.getLeftOperand().getType() instanceof StringType and
|
||||
v = e.getTargetVariable()
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ predicate cookieAppendHttpOnlyByDefault() {
|
||||
|
||||
predicate httpOnlyFalse(ObjectCreation oc) {
|
||||
exists(Assignment a |
|
||||
getAValueForProp(oc, a, "HttpOnly") = a.getRValue() and
|
||||
a.getRValue().getValue() = "false"
|
||||
getAValueForProp(oc, a, "HttpOnly") = a.getRightOperand() and
|
||||
a.getRightOperand().getValue() = "false"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -100,8 +100,8 @@ predicate nonHttpOnlyCookieBuilderAssignment(Assignment a, Expr val) {
|
||||
MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions
|
||||
) and
|
||||
pw.getProperty().getName() = "HttpOnly" and
|
||||
a.getLValue() = pw and
|
||||
DataFlow::localExprFlow(val, a.getRValue())
|
||||
a.getLeftOperand() = pw and
|
||||
DataFlow::localExprFlow(val, a.getRightOperand())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ where
|
||||
nonHttpOnlyCookieCall(httpOnlySink)
|
||||
or
|
||||
exists(Assignment a |
|
||||
httpOnlySink = a.getRValue() and
|
||||
httpOnlySink = a.getRightOperand() and
|
||||
nonHttpOnlyCookieBuilderAssignment(a, _)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -35,8 +35,8 @@ module InsecureSqlConnectionConfig implements DataFlow::ConfigSig {
|
||||
) and
|
||||
not exists(MemberInitializer mi |
|
||||
mi = oc.getInitializer().(ObjectInitializer).getAMemberInitializer() and
|
||||
mi.getLValue().(PropertyAccess).getTarget().getName() = "Encrypt" and
|
||||
mi.getRValue().(BoolLiteral).getValue() = "true"
|
||||
mi.getLeftOperand().(PropertyAccess).getTarget().getName() = "Encrypt" and
|
||||
mi.getRightOperand().(BoolLiteral).getValue() = "true"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ predicate cookieAppendSecureByDefault() {
|
||||
|
||||
predicate secureFalse(ObjectCreation oc) {
|
||||
exists(Assignment a |
|
||||
getAValueForProp(oc, a, "Secure") = a.getRValue() and
|
||||
a.getRValue().getValue() = "false"
|
||||
getAValueForProp(oc, a, "Secure") = a.getRightOperand() and
|
||||
a.getRightOperand().getValue() = "false"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,8 +96,8 @@ predicate insecureSecurePolicyAssignment(Assignment a, Expr val) {
|
||||
MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions
|
||||
) and
|
||||
pw.getProperty().getName() = "SecurePolicy" and
|
||||
a.getLValue() = pw and
|
||||
DataFlow::localExprFlow(val, a.getRValue()) and
|
||||
a.getLeftOperand() = pw and
|
||||
DataFlow::localExprFlow(val, a.getRightOperand()) and
|
||||
val.getValue() = "2" // None
|
||||
)
|
||||
}
|
||||
@@ -107,7 +107,7 @@ where
|
||||
insecureCookieCall(secureSink)
|
||||
or
|
||||
exists(Assignment a |
|
||||
secureSink = a.getRValue() and
|
||||
secureSink = a.getRightOperand() and
|
||||
insecureSecurePolicyAssignment(a, _)
|
||||
)
|
||||
select secureSink, "Cookie attribute 'Secure' is not set to true."
|
||||
|
||||
@@ -14,11 +14,11 @@ import csharp
|
||||
|
||||
from Assignment a, PropertyAccess pa
|
||||
where
|
||||
a.getLValue() = pa and
|
||||
a.getLeftOperand() = pa and
|
||||
pa.getTarget().hasName("Domain") and
|
||||
pa.getTarget().getDeclaringType().hasFullyQualifiedName("System.Web", "HttpCookie") and
|
||||
(
|
||||
a.getRValue().getValue().regexpReplaceAll("[^.]", "").length() < 2 or
|
||||
a.getRValue().getValue().matches(".%")
|
||||
a.getRightOperand().getValue().regexpReplaceAll("[^.]", "").length() < 2 or
|
||||
a.getRightOperand().getValue().matches(".%")
|
||||
)
|
||||
select a, "Overly broad domain for cookie."
|
||||
|
||||
@@ -14,8 +14,8 @@ import csharp
|
||||
|
||||
from Assignment a, PropertyAccess pa
|
||||
where
|
||||
a.getLValue() = pa and
|
||||
a.getLeftOperand() = pa and
|
||||
pa.getTarget().hasName("Path") and
|
||||
pa.getTarget().getDeclaringType().hasFullyQualifiedName("System.Web", "HttpCookie") and
|
||||
a.getRValue().getValue() = "/"
|
||||
a.getRightOperand().getValue() = "/"
|
||||
select a, "Overly broad path for cookie."
|
||||
|
||||
@@ -17,12 +17,12 @@ from Element l
|
||||
where
|
||||
// header checking is disabled programmatically in the code
|
||||
exists(Assignment a, PropertyAccess pa |
|
||||
a.getLValue() = pa and
|
||||
a.getLeftOperand() = pa and
|
||||
pa.getTarget().hasName("EnableHeaderChecking") and
|
||||
pa.getTarget()
|
||||
.getDeclaringType()
|
||||
.hasFullyQualifiedName("System.Web.Configuration", "HttpRuntimeSection") and
|
||||
a.getRValue().getValue() = "false" and
|
||||
a.getRightOperand().getValue() = "false" and
|
||||
a = l
|
||||
)
|
||||
or
|
||||
|
||||
@@ -89,10 +89,10 @@ module Random {
|
||||
e = any(SensitiveLibraryParameter v).getAnAssignedArgument()
|
||||
or
|
||||
// Assignment operation, e.g. += or similar
|
||||
exists(AssignOperation ao | ao.getRValue() = e |
|
||||
ao.getLValue() = any(SensitiveVariable v).getAnAccess() or
|
||||
ao.getLValue() = any(SensitiveProperty v).getAnAccess() or
|
||||
ao.getLValue() = any(SensitiveLibraryParameter v).getAnAccess()
|
||||
exists(AssignOperation ao | ao.getRightOperand() = e |
|
||||
ao.getLeftOperand() = any(SensitiveVariable v).getAnAccess() or
|
||||
ao.getLeftOperand() = any(SensitiveProperty v).getAnAccess() or
|
||||
ao.getLeftOperand() = any(SensitiveLibraryParameter v).getAnAccess()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ predicate incorrectUseOfRC2(Assignment e, string msg) {
|
||||
.getDeclaringType()
|
||||
.hasFullyQualifiedName("System.Security.Cryptography", "RC2CryptoServiceProvider")
|
||||
) and
|
||||
e.getRValue().getValue().toInt() < 128 and
|
||||
e.getRightOperand().getIntValue() < 128 and
|
||||
msg = "Key size should be at least 128 bits for RC2 encryption."
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ predicate incorrectUseOfDsa(ObjectCreation e, string msg) {
|
||||
e.getTarget()
|
||||
.getDeclaringType()
|
||||
.hasFullyQualifiedName("System.Security.Cryptography", "DSACryptoServiceProvider") and
|
||||
exists(Expr i | e.getArgument(0) = i and i.getValue().toInt() < 2048) and
|
||||
exists(Expr i | e.getArgument(0) = i and i.getIntValue() < 2048) and
|
||||
msg = "Key size should be at least 2048 bits for DSA encryption."
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ predicate incorrectUseOfRsa(ObjectCreation e, string msg) {
|
||||
e.getTarget()
|
||||
.getDeclaringType()
|
||||
.hasFullyQualifiedName("System.Security.Cryptography", "RSACryptoServiceProvider") and
|
||||
exists(Expr i | e.getArgument(0) = i and i.getValue().toInt() < 2048) and
|
||||
exists(Expr i | e.getArgument(0) = i and i.getIntValue() < 2048) and
|
||||
msg = "Key size should be at least 2048 bits for RSA encryption."
|
||||
}
|
||||
|
||||
|
||||
@@ -52,8 +52,8 @@ class FutureDateExpr extends MethodCall {
|
||||
|
||||
from Assignment a, PropertyAccess pa, FutureDateExpr fde
|
||||
where
|
||||
a.getLValue() = pa and
|
||||
a.getRValue() = fde and
|
||||
a.getLeftOperand() = pa and
|
||||
a.getRightOperand() = fde and
|
||||
pa.getTarget().hasName("Expires") and
|
||||
pa.getTarget().getDeclaringType().hasFullyQualifiedName("System.Web", "HttpCookie") and
|
||||
(fde.timeIsNotClear() or fde.getTimeInSecond() > 300) // 5 minutes max
|
||||
|
||||
@@ -27,7 +27,7 @@ module CallTargetStats implements StatsSig {
|
||||
p = c.getProperty() and
|
||||
not p.getAnAccessor() instanceof Setter and
|
||||
assign = c.getParent() and
|
||||
assign.getLValue() = c and
|
||||
assign.getLeftOperand() = c and
|
||||
assign.getParent() instanceof Property
|
||||
)
|
||||
}
|
||||
@@ -36,7 +36,7 @@ module CallTargetStats implements StatsSig {
|
||||
exists(Property p, AssignExpr assign |
|
||||
p = c.getProperty() and
|
||||
assign = c.getParent() and
|
||||
assign.getLValue() = c and
|
||||
assign.getLeftOperand() = c and
|
||||
assign.getParent() instanceof ObjectInitializer and
|
||||
assign.getParent().getParent() instanceof AnonymousObjectCreation
|
||||
)
|
||||
@@ -46,8 +46,8 @@ module CallTargetStats implements StatsSig {
|
||||
exists(Property p, AssignExpr assign |
|
||||
p = c.getProperty() and
|
||||
assign = c.getParent() and
|
||||
assign.getLValue() = c and
|
||||
assign.getRValue() instanceof ObjectOrCollectionInitializer
|
||||
assign.getLeftOperand() = c and
|
||||
assign.getRightOperand() instanceof ObjectOrCollectionInitializer
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -187,10 +187,10 @@ module HashWithoutSaltConfig implements DataFlow::ConfigSig {
|
||||
or
|
||||
// a salt or key is included in subclasses of `KeyedHashAlgorithm`
|
||||
exists(MethodCall mc, Assignment a, ObjectCreation oc |
|
||||
a.getRValue() = oc and
|
||||
a.getRightOperand() = oc and
|
||||
oc.getObjectType().getABaseType+() instanceof KeyedHashAlgorithm and
|
||||
mc.getTarget() instanceof HashMethod and
|
||||
a.getLValue() = mc.getQualifier().(VariableAccess).getTarget().getAnAccess() and
|
||||
a.getLeftOperand() = mc.getQualifier().(VariableAccess).getTarget().getAnAccess() and
|
||||
mc.getArgument(0) = node.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import csharp
|
||||
|
||||
from AssignOperation ao
|
||||
select ao, ao.getLValue(), ao.getRValue()
|
||||
select ao, ao.getLeftOperand(), ao.getRightOperand()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import csharp
|
||||
|
||||
from Assignment a
|
||||
select a.getLocation(), a.getLValue().getType().toString(), a.getRValue().getType().toString(),
|
||||
a.getRValue().toString()
|
||||
select a.getLocation(), a.getLeftOperand().getType().toString(),
|
||||
a.getRightOperand().getType().toString(), a.getRightOperand().toString()
|
||||
|
||||
@@ -3,7 +3,7 @@ import csharp
|
||||
private predicate getLambda(
|
||||
LocalVariableDeclAndInitExpr e, string type, LocalVariable v, LambdaExpr lexp
|
||||
) {
|
||||
lexp = e.getRValue() and
|
||||
lexp = e.getRightOperand() and
|
||||
v = e.getTargetVariable() and
|
||||
type = e.getType().toStringWithTypes()
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ query predicate assignbitwise(
|
||||
AssignBitwiseOperation op, Expr left, Expr right, string name, string qlclass
|
||||
) {
|
||||
op.getFile().getStem() = "Operators" and
|
||||
left = op.getLValue() and
|
||||
right = op.getRValue() and
|
||||
left = op.getLeftOperand() and
|
||||
right = op.getRightOperand() and
|
||||
name = op.getOperator() and
|
||||
qlclass = op.getAPrimaryQlClass()
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user