mirror of
https://github.com/github/codeql.git
synced 2026-06-03 04:40:14 +02:00
Compare commits
7 Commits
dependabot
...
tausbn/pyt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca59ca0c2f | ||
|
|
205466d7ab | ||
|
|
3e7986a14a | ||
|
|
ec9e72ee09 | ||
|
|
6efedb7d00 | ||
|
|
993311e436 | ||
|
|
e14d493bcc |
@@ -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.50.0")
|
||||
bazel_dep(name = "gazelle", version = "0.47.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,23 +26,10 @@ 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 jobHasPermissions(job) and
|
||||
not exists(job.getPermissions()) and
|
||||
not exists(job.getEnclosingWorkflow().getPermissions()) 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 source.getNode(), source, sink,
|
||||
"Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@).",
|
||||
event, event.getName()
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential artifact poisoning in $@, which may be controlled by an external user ($@).", sink,
|
||||
sink.getNode().toString(), event, event.getName()
|
||||
|
||||
@@ -20,5 +20,6 @@ from ArtifactPoisoningFlow::PathNode source, ArtifactPoisoningFlow::PathNode sin
|
||||
where
|
||||
ArtifactPoisoningFlow::flowPath(source, sink) and
|
||||
inNonPrivilegedContext(sink.getNode().asExpr())
|
||||
select source.getNode(), source, sink,
|
||||
"Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user."
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential artifact poisoning in $@, which may be controlled by an external user.", sink,
|
||||
sink.getNode().toString()
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `actions/missing-workflow-permissions` no longer produces false positive results on reusable workflows where all callers set permissions.
|
||||
@@ -1,9 +0,0 @@
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/deploy-pages
|
||||
@@ -1,11 +0,0 @@
|
||||
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/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 |
|
||||
| .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 |
|
||||
|
||||
@@ -7,12 +7,10 @@ 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
|
||||
@@ -30,7 +28,6 @@ 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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.1
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/integer-multiplication-cast-to-long
|
||||
* @tags reliability
|
||||
* security
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/wrong-type-format-argument
|
||||
* @tags reliability
|
||||
* correctness
|
||||
|
||||
@@ -14,9 +14,6 @@ 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>
|
||||
@@ -29,4 +26,4 @@ no results on those databases.</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 high
|
||||
* @precision medium
|
||||
* @id cpp/implicit-function-declaration
|
||||
* @tags correctness
|
||||
* maintainability
|
||||
@@ -17,11 +17,6 @@ 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
|
||||
@@ -44,7 +39,6 @@ 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,7 +79,9 @@ private predicate hasZeroParamDecl(Function f) {
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
private predicate isCompiledAsC(File f) {
|
||||
exists(File src | src.compiledAsC() | src.getAnIncludedFile*() = f)
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
predicate mistypedFunctionArguments(FunctionCall fc, Function f, Parameter p) {
|
||||
|
||||
@@ -28,7 +28,9 @@ private predicate hasZeroParamDecl(Function f) {
|
||||
|
||||
/* Holds if this file (or header) was compiled as a C file. */
|
||||
private predicate isCompiledAsC(File f) {
|
||||
exists(File src | src.compiledAsC() | src.getAnIncludedFile*() = f)
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
/** Holds if `fc` is a call to `f` with too few arguments. */
|
||||
|
||||
@@ -19,7 +19,9 @@ private predicate hasZeroParamDecl(Function f) {
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
private predicate isCompiledAsC(File f) {
|
||||
exists(File src | src.compiledAsC() | src.getAnIncludedFile*() = f)
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
predicate tooManyArguments(FunctionCall fc, Function f) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.8
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-190
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Implicit function declaration" (`cpp/implicit-function-declaration`) query has been upgraded to `high` precision.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -232,9 +232,14 @@ private module Identity {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate convTypeArguments(Type fromTypeArgument, Type toTypeArgument, int i) {
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, pragma[only_bind_into](i)) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, pragma[only_bind_into](i)) and
|
||||
convIdentity(fromTypeArgument, toTypeArgument)
|
||||
exists(int j |
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, i) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, j) and
|
||||
i <= j and
|
||||
j <= i
|
||||
|
|
||||
convIdentity(fromTypeArgument, toTypeArgument)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -924,16 +929,19 @@ private module Variance {
|
||||
private predicate convTypeArguments(
|
||||
TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i, TVariance v
|
||||
) {
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, pragma[only_bind_into](i), _) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, pragma[only_bind_into](i), _) and
|
||||
(
|
||||
exists(int j |
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, i, _) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, j, _) and
|
||||
i <= j and
|
||||
j <= i
|
||||
|
|
||||
convIdentity(fromTypeArgument, toTypeArgument) and
|
||||
v = TNone()
|
||||
or
|
||||
convRefTypeTypeArgumentOut(fromTypeArgument, toTypeArgument, i) and
|
||||
convRefTypeTypeArgumentOut(fromTypeArgument, toTypeArgument, j) and
|
||||
v = TOut()
|
||||
or
|
||||
convRefTypeTypeArgumentIn(toTypeArgument, fromTypeArgument, i) and
|
||||
convRefTypeTypeArgumentIn(toTypeArgument, fromTypeArgument, j) and
|
||||
v = TIn()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,8 +29,4 @@ module CsharpDataFlow implements InputSig<Location> {
|
||||
predicate neverSkipInPathGraph(Node n) {
|
||||
exists(n.(AssignableDefinitionNode).getDefinition().getTargetAccess())
|
||||
}
|
||||
|
||||
DataFlowType getSourceContextParameterNodeType(Node p) {
|
||||
exists(p) and result.isSourceContextParameterType()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1179,8 +1179,7 @@ private module Cached {
|
||||
cached
|
||||
newtype TDataFlowType =
|
||||
TGvnDataFlowType(Gvn::GvnType t) or
|
||||
TDelegateDataFlowType(Callable lambda) { lambdaCreationExpr(_, lambda) } or
|
||||
TSourceContextParameterType()
|
||||
TDelegateDataFlowType(Callable lambda) { lambdaCreationExpr(_, lambda) }
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -2395,8 +2394,6 @@ class DataFlowType extends TDataFlowType {
|
||||
|
||||
Callable asDelegate() { this = TDelegateDataFlowType(result) }
|
||||
|
||||
predicate isSourceContextParameterType() { this = TSourceContextParameterType() }
|
||||
|
||||
/**
|
||||
* Gets an expression that creates a delegate of this type.
|
||||
*
|
||||
@@ -2415,9 +2412,6 @@ class DataFlowType extends TDataFlowType {
|
||||
result = this.asGvnType().toString()
|
||||
or
|
||||
result = this.asDelegate().toString()
|
||||
or
|
||||
this.isSourceContextParameterType() and
|
||||
result = "<source context parameter type>"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2475,11 +2469,6 @@ 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`.
|
||||
@@ -2510,10 +2499,6 @@ predicate compatibleTypes(DataFlowType dt1, DataFlowType dt2) {
|
||||
compatibleTypesDelegateLeft(dt2, dt1)
|
||||
or
|
||||
dt1.asDelegate() = dt2.asDelegate()
|
||||
or
|
||||
compatibleTypesSourceContextParameterTypeLeft(dt1, dt2)
|
||||
or
|
||||
compatibleTypesSourceContextParameterTypeLeft(dt2, dt1)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2526,8 +2511,6 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
||||
uselessTypebound(t2)
|
||||
or
|
||||
compatibleTypesDelegateLeft(t1, t2)
|
||||
or
|
||||
compatibleTypesSourceContextParameterTypeLeft(t1, t2)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -536,12 +536,6 @@ public class HigherOrderParameters
|
||||
{
|
||||
a(o);
|
||||
}
|
||||
|
||||
private void CallApply()
|
||||
{
|
||||
// Test that this call to `Apply` does not interfere with the flow summaries generated for `Apply`
|
||||
Apply(x => x, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HigherOrderExtensionMethods
|
||||
|
||||
@@ -11,23 +11,23 @@
|
||||
Microsoft extensions (up to VS 2022),
|
||||
|
||||
Arm Compiler 5 [5]_","``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``"
|
||||
C#,C# up to 14 [6]_,"Microsoft Visual Studio up to 2019 with .NET up to 4.8,
|
||||
C#,C# up to 13,"Microsoft Visual Studio up to 2019 with .NET up to 4.8,
|
||||
|
||||
.NET Core up to 3.1
|
||||
|
||||
.NET 5, .NET 6, .NET 7, .NET 8, .NET 9, .NET 10 [6]_","``.sln``, ``.slnx``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
|
||||
.NET 5, .NET 6, .NET 7, .NET 8, .NET 9","``.sln``, ``.slnx``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
|
||||
GitHub Actions,"Not applicable",Not applicable,"``.github/workflows/*.yml``, ``.github/workflows/*.yaml``, ``**/action.yml``, ``**/action.yaml``"
|
||||
Go (aka Golang), "Go up to 1.26", "Go 1.11 or more recent", ``.go``
|
||||
Java,"Java 7 to 26 [7]_","javac (OpenJDK and Oracle JDK),
|
||||
Java,"Java 7 to 26 [6]_","javac (OpenJDK and Oracle JDK),
|
||||
|
||||
Eclipse compiler for Java (ECJ) [8]_",``.java``
|
||||
Eclipse compiler for Java (ECJ) [7]_",``.java``
|
||||
Kotlin,"Kotlin 1.8.0 to 2.3.2\ *x*","kotlinc",``.kt``
|
||||
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [9]_"
|
||||
Python [10]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py``
|
||||
Ruby [11]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"
|
||||
Rust [12]_,"Rust editions 2021 and 2024","Rust compiler","``.rs``, ``Cargo.toml``"
|
||||
Swift [13]_ [14]_,"Swift 5.4-6.2","Swift compiler","``.swift``"
|
||||
TypeScript [15]_,"2.6-5.9",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``"
|
||||
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [8]_"
|
||||
Python [9]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py``
|
||||
Ruby [10]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"
|
||||
Rust [11]_,"Rust editions 2021 and 2024","Rust compiler","``.rs``, ``Cargo.toml``"
|
||||
Swift [12]_ [13]_,"Swift 5.4-6.2","Swift compiler","``.swift``"
|
||||
TypeScript [14]_,"2.6-5.9",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``"
|
||||
|
||||
.. container:: footnote-group
|
||||
|
||||
@@ -36,13 +36,12 @@
|
||||
.. [3] Objective-C, Objective-C++, C++/CLI, and C++/CX are not supported.
|
||||
.. [4] Support for the clang-cl compiler is preliminary.
|
||||
.. [5] Support for the Arm Compiler (armcc) is preliminary.
|
||||
.. [6] Support for .NET 10 is preliminary and code that uses language features new to C# 14 is not yet fully supported for extraction and analysis.
|
||||
.. [7] Builds that execute on Java 7 to 26 can be analyzed. The analysis understands standard language features in Java 8 to 26; "preview" and "incubator" features are not supported. Source code using Java language versions older than Java 8 are analyzed as Java 8 code.
|
||||
.. [8] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin.
|
||||
.. [9] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
|
||||
.. [10] The extractor requires Python 3 to run. To analyze Python 2.7 you should install both versions of Python.
|
||||
.. [11] Requires glibc 2.17.
|
||||
.. [12] Requires ``rustup`` and ``cargo`` to be installed. Features from nightly toolchains are not supported.
|
||||
.. [13] Support for the analysis of Swift requires macOS.
|
||||
.. [14] Embedded Swift is not supported.
|
||||
.. [15] TypeScript analysis is performed by running the JavaScript extractor with TypeScript enabled. This is the default.
|
||||
.. [6] Builds that execute on Java 7 to 26 can be analyzed. The analysis understands standard language features in Java 8 to 26; "preview" and "incubator" features are not supported. Source code using Java language versions older than Java 8 are analyzed as Java 8 code.
|
||||
.. [7] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin.
|
||||
.. [8] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
|
||||
.. [9] The extractor requires Python 3 to run. To analyze Python 2.7 you should install both versions of Python.
|
||||
.. [10] Requires glibc 2.17.
|
||||
.. [11] Requires ``rustup`` and ``cargo`` to be installed. Features from nightly toolchains are not supported.
|
||||
.. [12] Support for the analysis of Swift requires macOS.
|
||||
.. [13] Embedded Swift is not supported.
|
||||
.. [14] TypeScript analysis is performed by running the JavaScript extractor with TypeScript enabled. This is the default.
|
||||
|
||||
@@ -191,21 +191,3 @@ class RouteHandlerLimitedByRateLimiterFlexible extends RateLimitingMiddleware in
|
||||
private class FastifyRateLimiter extends RateLimitingMiddleware {
|
||||
FastifyRateLimiter() { this = DataFlow::moduleImport("fastify-rate-limit") }
|
||||
}
|
||||
|
||||
/**
|
||||
* An options object with a `rateLimit` config passed to a Fastify shorthand route method,
|
||||
* such as `fastify.post('/path', { config: { rateLimit: { ... } } }, handler)`.
|
||||
*/
|
||||
private class FastifyPerRouteRateLimit extends RateLimitingMiddleware {
|
||||
FastifyPerRouteRateLimit() {
|
||||
exists(Fastify::RouteSetup setup |
|
||||
not setup.getMethodName() = ["route", "addHook"] and
|
||||
setup.getNumArgument() >= 3 and
|
||||
this.flowsTo(setup.getArgument(1))
|
||||
|
|
||||
exists(this.getAPropertySource("config").getAPropertySource("rateLimit"))
|
||||
or
|
||||
exists(this.getAPropertySource("rateLimit"))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `js/missing-rate-limiting` now takes Fastify per-route
|
||||
rate limiting into account.
|
||||
@@ -9,4 +9,3 @@
|
||||
| tst.js:64:25:64:63 | functio ... req); } | This route handler performs $@, but is not rate-limited. | tst.js:64:46:64:60 | verifyUser(req) | authorization |
|
||||
| tst.js:76:25:76:53 | catchAs ... ndler1) | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization |
|
||||
| tst.js:88:24:88:40 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization |
|
||||
| tst.js:112:28:112:44 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization |
|
||||
|
||||
@@ -88,25 +88,3 @@ const fastifyApp = require('fastify')();
|
||||
fastifyApp.get('/foo', expensiveHandler1); // $ Alert
|
||||
fastifyApp.register(require('fastify-rate-limit'));
|
||||
fastifyApp.get('/bar', expensiveHandler1);
|
||||
|
||||
// Fastify per-route rate limiting via config.rateLimit
|
||||
const fastifyApp2 = require('fastify')();
|
||||
fastifyApp2.register(require('@fastify/rate-limit'));
|
||||
|
||||
fastifyApp2.post('/login', {
|
||||
config: {
|
||||
rateLimit: {
|
||||
max: 3,
|
||||
timeWindow: '1 minute'
|
||||
}
|
||||
}
|
||||
}, expensiveHandler1); // OK - has per-route rateLimit config
|
||||
|
||||
fastifyApp2.post('/signup', {
|
||||
rateLimit: {
|
||||
max: 5,
|
||||
timeWindow: '1 minute'
|
||||
}
|
||||
}, expensiveHandler1); // OK - has per-route rateLimit directly in options
|
||||
|
||||
fastifyApp2.post('/other', expensiveHandler1); // $ Alert - no rate limiting
|
||||
|
||||
@@ -14,7 +14,7 @@ pluggy==1.5.0
|
||||
# via pytest
|
||||
pystache==0.6.8
|
||||
# via -r misc/codegen/requirements_in.txt
|
||||
pytest==9.0.3
|
||||
pytest==8.3.5
|
||||
# via -r misc/codegen/requirements_in.txt
|
||||
pyyaml==6.0.2
|
||||
# via -r misc/codegen/requirements_in.txt
|
||||
|
||||
@@ -1988,6 +1988,38 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall
|
||||
module DuckTyping {
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/**
|
||||
* Holds if `name` is a globally defined name (a builtin or VM-defined name).
|
||||
*/
|
||||
predicate globallyDefinedName(string name) {
|
||||
exists(API::builtin(name))
|
||||
or
|
||||
name = "WindowsError"
|
||||
or
|
||||
name = "_" and exists(Module m | m.getName() = "gettext")
|
||||
or
|
||||
name in ["__file__", "__builtins__", "__name__"]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` is monkey-patched into the builtins module.
|
||||
*/
|
||||
predicate monkeyPatchedBuiltin(string name) {
|
||||
any(DataFlow::AttrWrite aw)
|
||||
.writes(API::moduleImport("builtins").getAValueReachableFromSource(), name, _)
|
||||
or
|
||||
// B.__dict__["name"] = value
|
||||
exists(SubscriptNode subscr |
|
||||
subscr.isStore() and
|
||||
subscr.getObject() =
|
||||
API::moduleImport("builtins")
|
||||
.getMember("__dict__")
|
||||
.getAValueReachableFromSource()
|
||||
.asCfgNode() and
|
||||
subscr.getIndex().getNode().(StringLiteral).getText() = name
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cls` or any of its resolved superclasses declares a method with the given `name`.
|
||||
*/
|
||||
@@ -2158,4 +2190,415 @@ module DuckTyping {
|
||||
or
|
||||
f.getADecorator().(Name).getId() = "property"
|
||||
}
|
||||
|
||||
/** Gets the name of the builtin class of the immutable literal `lit`. */
|
||||
string getClassName(ImmutableLiteral lit) {
|
||||
lit instanceof IntegerLiteral and result = "int"
|
||||
or
|
||||
lit instanceof FloatLiteral and result = "float"
|
||||
or
|
||||
lit instanceof ImaginaryLiteral and result = "complex"
|
||||
or
|
||||
lit instanceof NegativeIntegerLiteral and result = "int"
|
||||
or
|
||||
lit instanceof StringLiteral and result = "str"
|
||||
or
|
||||
lit instanceof BooleanLiteral and result = "bool"
|
||||
or
|
||||
lit instanceof None and result = "NoneType"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a class hierarchy for exception types, covering both builtin
|
||||
* exceptions (from typeshed models) and user-defined exception classes.
|
||||
*/
|
||||
module ExceptionTypes {
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.frameworks.data.internal.ApiGraphModels
|
||||
|
||||
/** Holds if `name` is a builtin exception class name. */
|
||||
predicate builtinException(string name) {
|
||||
typeModel("builtins.BaseException~Subclass", "builtins." + name, "")
|
||||
}
|
||||
|
||||
/** Holds if builtin exception `sub` is a direct subclass of builtin exception `base`. */
|
||||
private predicate builtinExceptionSubclass(string base, string sub) {
|
||||
typeModel("builtins." + base + "~Subclass", "builtins." + sub, "")
|
||||
}
|
||||
|
||||
/** An exception type, either a builtin exception or a user-defined exception class. */
|
||||
newtype TExceptType =
|
||||
/** A user-defined exception class. */
|
||||
TUserExceptType(Class c) or
|
||||
/** A builtin exception class, identified by name. */
|
||||
TBuiltinExceptType(string name) { builtinException(name) }
|
||||
|
||||
/** An exception type, either a builtin exception or a user-defined exception class. */
|
||||
class ExceptType extends TExceptType {
|
||||
/** Gets the name of this exception type. */
|
||||
string getName() { none() }
|
||||
|
||||
/** Gets a data-flow node that refers to this exception type. */
|
||||
DataFlow::Node getAUse() { none() }
|
||||
|
||||
/** Gets a direct superclass of this exception type. */
|
||||
ExceptType getADirectSuperclass() { none() }
|
||||
|
||||
/** Gets a string representation of this exception type. */
|
||||
string toString() { result = this.getName() }
|
||||
|
||||
/** Gets a data-flow node that refers to an instance of this exception type. */
|
||||
DataFlow::Node getAnInstance() { none() }
|
||||
|
||||
/** Holds if this is a legal exception type (a subclass of `BaseException`). */
|
||||
predicate isLegalExceptionType() { this.getADirectSuperclass*() instanceof BaseException }
|
||||
|
||||
/**
|
||||
* Holds if this exception type is raised by `r`, either as a class reference
|
||||
* (e.g. `raise ValueError`) or as an instantiation (e.g. `raise ValueError("msg")`).
|
||||
*/
|
||||
predicate isRaisedBy(Raise r) {
|
||||
exists(Expr raised | raised = r.getRaised() |
|
||||
this.getAUse().asExpr() in [raised, raised.(Call).getFunc()]
|
||||
or
|
||||
this.getAnInstance().asExpr() = raised
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this exception type may be raised at control flow node `r`. */
|
||||
predicate isRaisedAt(ControlFlowNode r) {
|
||||
this.isRaisedBy(r.getNode())
|
||||
or
|
||||
exists(Function callee |
|
||||
resolveCall(r, callee, _) and
|
||||
this.isRaisedIn(callee)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this exception type may be raised in function `f`, either
|
||||
* directly via `raise` statements or transitively through calls to other functions.
|
||||
*/
|
||||
predicate isRaisedIn(Function f) { this.isRaisedAt(any(ControlFlowNode r | r.getScope() = f)) }
|
||||
|
||||
/** Holds if this exception type is handled by the `except` clause at `handler`. */
|
||||
predicate isHandledAt(ExceptFlowNode handler) {
|
||||
exists(ExceptStmt ex, Expr typeExpr | ex = handler.getNode() |
|
||||
(
|
||||
typeExpr = ex.getType()
|
||||
or
|
||||
typeExpr = ex.getType().(Tuple).getAnElt()
|
||||
) and
|
||||
this.getAUse().asExpr() = typeExpr
|
||||
)
|
||||
or
|
||||
// A bare `except:` handles everything
|
||||
not exists(handler.getNode().(ExceptStmt).getType()) and
|
||||
this instanceof BaseException
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startColumn` of line `startLine` to
|
||||
* column `endColumn` of line `endLine` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filePath, int startLine, int startColumn, int endLine, int endColumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/** A user-defined exception class. */
|
||||
class UserExceptType extends ExceptType, TUserExceptType {
|
||||
Class cls;
|
||||
|
||||
UserExceptType() { this = TUserExceptType(cls) }
|
||||
|
||||
/** Gets the underlying class. */
|
||||
Class asClass() { result = cls }
|
||||
|
||||
override string getName() { result = cls.getName() }
|
||||
|
||||
override DataFlow::Node getAUse() { result = classTracker(cls) }
|
||||
|
||||
override DataFlow::Node getAnInstance() { result = classInstanceTracker(cls) }
|
||||
|
||||
override ExceptType getADirectSuperclass() {
|
||||
result.(UserExceptType).asClass() = getADirectSuperclass(cls)
|
||||
or
|
||||
result.(BuiltinExceptType).getAUse().asExpr() = cls.getABase()
|
||||
}
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filePath, int startLine, int startColumn, int endLine, int endColumn
|
||||
) {
|
||||
cls.getLocation().hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
|
||||
}
|
||||
}
|
||||
|
||||
/** A builtin exception class, identified by name. */
|
||||
class BuiltinExceptType extends ExceptType, TBuiltinExceptType {
|
||||
string name;
|
||||
|
||||
BuiltinExceptType() { this = TBuiltinExceptType(name) }
|
||||
|
||||
/** Gets the builtin name. */
|
||||
string asBuiltinName() { result = name }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override DataFlow::Node getAUse() { result = API::builtin(name).getAValueReachableFromSource() }
|
||||
|
||||
override DataFlow::Node getAnInstance() {
|
||||
result = API::builtin(name).getAnInstance().getAValueReachableFromSource()
|
||||
}
|
||||
|
||||
override ExceptType getADirectSuperclass() {
|
||||
builtinExceptionSubclass(result.(BuiltinExceptType).asBuiltinName(), name) and
|
||||
result != this
|
||||
}
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filePath, int startLine, int startColumn, int endLine, int endColumn
|
||||
) {
|
||||
filePath = "" and
|
||||
startLine = 0 and
|
||||
startColumn = 0 and
|
||||
endLine = 0 and
|
||||
endColumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
/** The builtin `BaseException` type. */
|
||||
class BaseException extends BuiltinExceptType {
|
||||
BaseException() { name = "BaseException" }
|
||||
}
|
||||
|
||||
/** The builtin `NameError` exception type. */
|
||||
class NameError extends BuiltinExceptType {
|
||||
NameError() { name = "NameError" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the exception edge from `r` to `handler` is unlikely because
|
||||
* none of the exception types that `r` may raise are handled by `handler`.
|
||||
*/
|
||||
predicate unlikelyExceptionEdge(ControlFlowNode r, ExceptFlowNode handler) {
|
||||
handler = r.getAnExceptionalSuccessor() and
|
||||
// We can determine at least one raised type
|
||||
exists(ExceptType t | t.isRaisedAt(r)) and
|
||||
// But none of them are handled by this handler
|
||||
not exists(ExceptType raised, ExceptType handled |
|
||||
raised.isRaisedAt(r) and
|
||||
handled.isHandledAt(handler) and
|
||||
raised.getADirectSuperclass*() = handled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides predicates for reasoning about the reachability of control flow nodes
|
||||
* and basic blocks.
|
||||
*/
|
||||
module Reachability {
|
||||
private import semmle.python.ApiGraphs
|
||||
import ExceptionTypes
|
||||
|
||||
/**
|
||||
* Holds if `call` is a call to a function that is known to never return normally
|
||||
* (e.g. `sys.exit()`, `os._exit()`, `os.abort()`).
|
||||
*/
|
||||
predicate isCallToNeverReturningFunction(CallNode call) {
|
||||
// Known never-returning builtins/stdlib functions via API graphs
|
||||
call = API::builtin("exit").getACall().asCfgNode()
|
||||
or
|
||||
call = API::builtin("quit").getACall().asCfgNode()
|
||||
or
|
||||
call = API::moduleImport("sys").getMember("exit").getACall().asCfgNode()
|
||||
or
|
||||
call = API::moduleImport("os").getMember("_exit").getACall().asCfgNode()
|
||||
or
|
||||
call = API::moduleImport("os").getMember("abort").getACall().asCfgNode()
|
||||
or
|
||||
// User-defined functions that only contain raise statements (no normal returns)
|
||||
exists(Function target |
|
||||
resolveCall(call, target, _) and
|
||||
neverReturns(target)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if function `f` never returns normally, because every normal exit
|
||||
* is dominated by a call to a never-returning function or an unconditional raise.
|
||||
*/
|
||||
predicate neverReturns(Function f) {
|
||||
exists(f.getANormalExit()) and
|
||||
forall(BasicBlock exit | exit = f.getANormalExit().getBasicBlock() |
|
||||
exists(BasicBlock raising |
|
||||
raising.dominates(exit) and
|
||||
(
|
||||
isCallToNeverReturningFunction(raising.getLastNode())
|
||||
or
|
||||
raising.getLastNode().getNode() instanceof Raise
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is unlikely to raise an exception. This includes entry nodes
|
||||
* and simple name lookups.
|
||||
*/
|
||||
private predicate unlikelyToRaise(ControlFlowNode node) {
|
||||
exists(node.getAnExceptionalSuccessor()) and
|
||||
(
|
||||
node.getNode() instanceof Name
|
||||
or
|
||||
exists(Scope s | s.getEntryNode() = node)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if it is highly unlikely for control to flow from `node` to `succ`.
|
||||
*/
|
||||
predicate unlikelySuccessor(ControlFlowNode node, ControlFlowNode succ) {
|
||||
// Exceptional edge where the raised type doesn't match the handler
|
||||
unlikelyExceptionEdge(node, succ)
|
||||
or
|
||||
// Normal successor of a never-returning call
|
||||
isCallToNeverReturningFunction(node) and
|
||||
succ = node.getASuccessor() and
|
||||
not succ = node.getAnExceptionalSuccessor() and
|
||||
not succ.getNode() instanceof Yield
|
||||
or
|
||||
// Exception edge from a node that is unlikely to raise
|
||||
unlikelyToRaise(node) and
|
||||
succ = node.getAnExceptionalSuccessor()
|
||||
or
|
||||
// True branch of `if False:` or `if TYPE_CHECKING:`
|
||||
isAlwaysFalseGuard(node) and
|
||||
succ = node.getATrueSuccessor()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is a condition that is always `False` at runtime.
|
||||
* This covers `if False:` and `if typing.TYPE_CHECKING:`.
|
||||
*/
|
||||
private predicate isAlwaysFalseGuard(ControlFlowNode node) {
|
||||
node.getNode() instanceof False
|
||||
or
|
||||
node =
|
||||
API::moduleImport("typing")
|
||||
.getMember("TYPE_CHECKING")
|
||||
.getAValueReachableFromSource()
|
||||
.asCfgNode()
|
||||
}
|
||||
|
||||
private predicate startBbLikelyReachable(BasicBlock b) {
|
||||
exists(Scope s | s.getEntryNode() = b.getNode(_))
|
||||
or
|
||||
exists(BasicBlock pred |
|
||||
pred = b.getAPredecessor() and
|
||||
endBbLikelyReachable(pred) and
|
||||
not unlikelySuccessor(pred.getLastNode(), b)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate endBbLikelyReachable(BasicBlock b) {
|
||||
startBbLikelyReachable(b) and
|
||||
not exists(ControlFlowNode p, ControlFlowNode s |
|
||||
unlikelySuccessor(p, s) and
|
||||
p = b.getNode(_) and
|
||||
s = b.getNode(_) and
|
||||
not p = b.getLastNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `b` is likely to be reachable from the entry of its
|
||||
* enclosing scope.
|
||||
*/
|
||||
predicate likelyReachable(BasicBlock b) { startBbLikelyReachable(b) }
|
||||
|
||||
/**
|
||||
* Holds if it is unlikely that `node` can be reached during execution.
|
||||
*/
|
||||
predicate unlikelyReachable(ControlFlowNode node) {
|
||||
not startBbLikelyReachable(node.getBasicBlock())
|
||||
or
|
||||
exists(BasicBlock b |
|
||||
startBbLikelyReachable(b) and
|
||||
not endBbLikelyReachable(b) and
|
||||
exists(ControlFlowNode p, int i, int j |
|
||||
unlikelySuccessor(p, _) and
|
||||
p = b.getNode(i) and
|
||||
node = b.getNode(j) and
|
||||
i < j
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `var` is an SSA variable that is implicitly defined (a builtin,
|
||||
* VM-defined name, or `__path__` in a package init).
|
||||
*/
|
||||
private predicate implicitlyDefined(SsaVariable var) {
|
||||
not exists(var.getDefinition()) and
|
||||
not py_ssa_phi(var, _) and
|
||||
exists(GlobalVariable gv | var.getVariable() = gv |
|
||||
DuckTyping::globallyDefinedName(gv.getId())
|
||||
or
|
||||
gv.getId() = "__path__" and gv.getScope().(Module).isPackageInit()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a phi input of `var`, pruned of unlikely edges.
|
||||
*/
|
||||
private SsaVariable getAPrunedPhiInput(SsaVariable var) {
|
||||
result = var.getAPhiInput() and
|
||||
exists(BasicBlock incoming | incoming = var.getPredecessorBlockForPhiArgument(result) |
|
||||
not unlikelySuccessor(incoming.getLastNode(), var.getDefinition().getBasicBlock().firstNode())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a predecessor block for a phi node, pruned of unlikely edges.
|
||||
*/
|
||||
private BasicBlock getAPrunedPredecessorBlockForPhi(SsaVariable var) {
|
||||
result = var.getAPredecessorBlockForPhi() and
|
||||
not unlikelySuccessor(result.getLastNode(), var.getDefinition().getBasicBlock().firstNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSA variable `var` may be undefined at some use.
|
||||
*/
|
||||
private predicate ssaMaybeUndefined(SsaVariable var) {
|
||||
// No definition, not a phi, not implicitly defined
|
||||
not exists(var.getDefinition()) and not py_ssa_phi(var, _) and not implicitlyDefined(var)
|
||||
or
|
||||
// Defined by a deletion
|
||||
var.getDefinition().isDelete()
|
||||
or
|
||||
// A phi input may be undefined
|
||||
exists(SsaVariable input | input = getAPrunedPhiInput(var) | ssaMaybeUndefined(input))
|
||||
or
|
||||
// A phi predecessor has no dominating definition
|
||||
exists(BasicBlock incoming |
|
||||
likelyReachable(incoming) and
|
||||
incoming = getAPrunedPredecessorBlockForPhi(var) and
|
||||
not var.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the name `u` may be undefined at its use.
|
||||
*/
|
||||
predicate maybeUndefined(Name u) {
|
||||
exists(SsaVariable var | var.getAUse().getNode() = u | ssaMaybeUndefined(var))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,74 +15,7 @@
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
import semmle.python.ApiGraphs
|
||||
import semmle.python.frameworks.data.internal.ApiGraphModels
|
||||
|
||||
predicate builtinException(string name) {
|
||||
typeModel("builtins.BaseException~Subclass", "builtins." + name, "")
|
||||
}
|
||||
|
||||
predicate builtinExceptionSubclass(string base, string sub) {
|
||||
typeModel("builtins." + base + "~Subclass", "builtins." + sub, "")
|
||||
}
|
||||
|
||||
newtype TExceptType =
|
||||
TClass(Class c) or
|
||||
TBuiltin(string name) { builtinException(name) }
|
||||
|
||||
class ExceptType extends TExceptType {
|
||||
Class asClass() { this = TClass(result) }
|
||||
|
||||
string asBuiltinName() { this = TBuiltin(result) }
|
||||
|
||||
predicate isBuiltin() { this = TBuiltin(_) }
|
||||
|
||||
string getName() {
|
||||
result = this.asClass().getName()
|
||||
or
|
||||
result = this.asBuiltinName()
|
||||
}
|
||||
|
||||
string toString() { result = this.getName() }
|
||||
|
||||
DataFlow::Node getAUse() {
|
||||
result = classTracker(this.asClass())
|
||||
or
|
||||
API::builtin(this.asBuiltinName()).asSource().flowsTo(result)
|
||||
}
|
||||
|
||||
ExceptType getADirectSuperclass() {
|
||||
result.asClass() = getADirectSuperclass(this.asClass())
|
||||
or
|
||||
result.isBuiltin() and
|
||||
result.getAUse().asExpr() = this.asClass().getABase()
|
||||
or
|
||||
builtinExceptionSubclass(result.asBuiltinName(), this.asBuiltinName()) and
|
||||
this != result
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startColumn` of line `startLine` to
|
||||
* column `endColumn` of line `endLine` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filePath, int startLine, int startColumn, int endLine, int endColumn
|
||||
) {
|
||||
this.asClass()
|
||||
.getLocation()
|
||||
.hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
|
||||
or
|
||||
this.isBuiltin() and
|
||||
filePath = "" and
|
||||
startLine = 0 and
|
||||
startColumn = 0 and
|
||||
endLine = 0 and
|
||||
endColumn = 0
|
||||
}
|
||||
}
|
||||
private import ExceptionTypes
|
||||
|
||||
predicate incorrectExceptOrder(ExceptStmt ex1, ExceptType cls1, ExceptStmt ex2, ExceptType cls2) {
|
||||
exists(int i, int j, Try t |
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import semmle.python.ApiGraphs
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate originIsLocals(ControlFlowNode n) {
|
||||
API::builtin("locals").getReturn().getAValueReachableFromSource().asCfgNode() = n
|
||||
predicate originIsLocals(ControlFlowNodeWithPointsTo n) {
|
||||
n.pointsTo(_, _, Value::named("locals").getACall())
|
||||
}
|
||||
|
||||
predicate modification_of_locals(ControlFlowNode f) {
|
||||
@@ -37,8 +37,5 @@ where
|
||||
// in module level scope `locals() == globals()`
|
||||
// see https://docs.python.org/3/library/functions.html#locals
|
||||
// FP report in https://github.com/github/codeql/issues/6674
|
||||
not a.getScope() instanceof Module and
|
||||
// in class level scope `locals()` reflects the class namespace,
|
||||
// so modifications do take effect.
|
||||
not a.getScope() instanceof Class
|
||||
not a.getScope() instanceof ModuleScope
|
||||
select a, "Modification of the locals() dictionary will have no effect on the local variables."
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import semmle.python.ApiGraphs
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate typing_import(ImportingStmt is) {
|
||||
exists(Module m |
|
||||
@@ -34,7 +34,11 @@ predicate unique_yield(Stmt s) {
|
||||
/** Holds if `contextlib.suppress` may be used in the same scope as `s` */
|
||||
predicate suppression_in_scope(Stmt s) {
|
||||
exists(With w |
|
||||
w.getContextExpr() = API::moduleImport("contextlib").getMember("suppress").getACall().asExpr() and
|
||||
w.getContextExpr()
|
||||
.(Call)
|
||||
.getFunc()
|
||||
.(ExprWithPointsTo)
|
||||
.pointsTo(Value::named("contextlib.suppress")) and
|
||||
w.getScope() = s.getScope()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,49 +12,11 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
private import semmle.python.dataflow.new.internal.Builtins
|
||||
private import semmle.python.ApiGraphs
|
||||
private import LegacyPointsTo
|
||||
|
||||
/**
|
||||
* Holds if `cls` is a user-defined exception class, i.e. it transitively
|
||||
* extends one of the builtin exception base classes.
|
||||
*/
|
||||
predicate isUserDefinedExceptionClass(Class cls) {
|
||||
cls.getABase() =
|
||||
API::builtin(["BaseException", "Exception"]).getAValueReachableFromSource().asExpr()
|
||||
or
|
||||
isUserDefinedExceptionClass(getADirectSuperclass(cls))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of a builtin exception class.
|
||||
*/
|
||||
string getBuiltinExceptionName() {
|
||||
result = Builtins::getBuiltinName() and
|
||||
(
|
||||
result.matches("%Error") or
|
||||
result.matches("%Exception") or
|
||||
result.matches("%Warning") or
|
||||
result =
|
||||
["GeneratorExit", "KeyboardInterrupt", "StopIteration", "StopAsyncIteration", "SystemExit"]
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is an instantiation of an exception class.
|
||||
*/
|
||||
predicate isExceptionInstantiation(Call call) {
|
||||
exists(Class cls |
|
||||
classTracker(cls).asExpr() = call.getFunc() and
|
||||
isUserDefinedExceptionClass(cls)
|
||||
)
|
||||
or
|
||||
call.getFunc() = API::builtin(getBuiltinExceptionName()).getAValueReachableFromSource().asExpr()
|
||||
}
|
||||
|
||||
from Call call
|
||||
from Call call, ClassValue ex
|
||||
where
|
||||
isExceptionInstantiation(call) and
|
||||
call.getFunc().(ExprWithPointsTo).pointsTo(ex) and
|
||||
ex.getASuperType() = ClassValue::exception() and
|
||||
exists(ExprStmt s | s.getValue() = call)
|
||||
select call, "Instantiating an exception, but not raising it, has no effect."
|
||||
|
||||
@@ -12,12 +12,10 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import semmle.python.ApiGraphs
|
||||
private import LegacyPointsTo
|
||||
|
||||
from CallNode call, string name
|
||||
where
|
||||
name = ["exit", "quit"] and
|
||||
call = API::builtin(name).getACall().asCfgNode()
|
||||
where call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(Value::siteQuitter(name))
|
||||
select call,
|
||||
"The '" + name +
|
||||
"' site.Quitter object may not exist if the 'site' module is not loaded or is modified."
|
||||
|
||||
@@ -174,9 +174,3 @@ def assert_ok(seq):
|
||||
# False positive. ODASA-8042. Fixed in PR #2401.
|
||||
class false_positive:
|
||||
e = (x for x in [])
|
||||
|
||||
# In class-level scope `locals()` reflects the class namespace,
|
||||
# so modifications do take effect.
|
||||
class MyClass:
|
||||
locals()['x'] = 43 # OK
|
||||
y = x
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Build a local Python extractor pack from source.
|
||||
#
|
||||
# Usage with the CodeQL CLI (run from the repository root):
|
||||
#
|
||||
# codeql database create <db> -l python -s <src> --search-path .
|
||||
# codeql test run --search-path . python/ql/test/<test-dir>
|
||||
#
|
||||
set -eux
|
||||
|
||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
platform="linux64"
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
platform="osx64"
|
||||
else
|
||||
echo "Unknown OS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
# Build the tsg-python Rust binary
|
||||
(cd extractor/tsg-python && cargo build --release)
|
||||
tsg_bin="extractor/tsg-python/target/release/tsg-python"
|
||||
|
||||
# Generate python3src.zip from the Python extractor source.
|
||||
# make_zips.py creates the zip in the source directory and then copies it to the
|
||||
# given output directory. We use a temporary directory to avoid a same-file copy
|
||||
# error, then move the zip back.
|
||||
tmpdir=$(mktemp -d)
|
||||
trap 'rm -rf "$tmpdir"' EXIT
|
||||
(cd extractor && python3 make_zips.py "$tmpdir")
|
||||
cp "$tmpdir/python3src.zip" extractor/python3src.zip
|
||||
|
||||
# Assemble the extractor pack
|
||||
rm -rf extractor-pack
|
||||
mkdir -p extractor-pack/tools/${platform}
|
||||
|
||||
# Root-level metadata and schema files
|
||||
cp codeql-extractor.yml extractor-pack/
|
||||
cp ql/lib/semmlecode.python.dbscheme extractor-pack/
|
||||
cp ql/lib/semmlecode.python.dbscheme.stats extractor-pack/
|
||||
|
||||
# Python extractor engine files (into tools/)
|
||||
cp extractor/python_tracer.py extractor-pack/tools/
|
||||
cp extractor/index.py extractor-pack/tools/
|
||||
cp extractor/setup.py extractor-pack/tools/
|
||||
cp extractor/convert_setup.py extractor-pack/tools/
|
||||
cp extractor/get_venv_lib.py extractor-pack/tools/
|
||||
cp extractor/imp.py extractor-pack/tools/
|
||||
cp extractor/LICENSE-PSF.md extractor-pack/tools/
|
||||
cp extractor/python3src.zip extractor-pack/tools/
|
||||
cp -r extractor/data extractor-pack/tools/
|
||||
|
||||
# Shell tool scripts (autobuild, pre-finalize, lgtm-scripts)
|
||||
cp tools/autobuild.sh extractor-pack/tools/
|
||||
cp tools/autobuild.cmd extractor-pack/tools/
|
||||
cp tools/pre-finalize.sh extractor-pack/tools/
|
||||
cp tools/pre-finalize.cmd extractor-pack/tools/
|
||||
cp -r tools/lgtm-scripts extractor-pack/tools/
|
||||
|
||||
# Downgrades
|
||||
cp -r downgrades extractor-pack/
|
||||
|
||||
# Platform-specific Rust binary
|
||||
cp "${tsg_bin}" extractor-pack/tools/${platform}/tsg-python
|
||||
@@ -45,16 +45,13 @@ extensible predicate additionalExternalFile(string relativePath);
|
||||
|
||||
/** A file. */
|
||||
class File extends Container, Impl::File {
|
||||
pragma[nomagic]
|
||||
private predicate isAdditionalExternalFile() { additionalExternalFile(this.getRelativePath()) }
|
||||
|
||||
/**
|
||||
* Holds if this file was extracted from the source code of the target project
|
||||
* (rather than another location such as inside a dependency).
|
||||
*/
|
||||
predicate fromSource() {
|
||||
exists(ExtractorStep s | s.getAction() = "Extract" and s.getFile() = this) and
|
||||
not this.isAdditionalExternalFile()
|
||||
not additionalExternalFile(this.getRelativePath())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,35 +63,6 @@ signature module InputSig<LocationSig Location> {
|
||||
|
||||
DataFlowType getNodeType(Node node);
|
||||
|
||||
/**
|
||||
* Gets a special type to use for parameter node `p` belonging to callables with a
|
||||
* source node where a source call context `FlowFeature` is used, if any.
|
||||
*
|
||||
* This can be used to prevent lambdas from being resolved, when a concrete call
|
||||
* context is needed. Example:
|
||||
*
|
||||
* ```csharp
|
||||
* void Foo(Action<string> a)
|
||||
* {
|
||||
* var x = Source();
|
||||
* a(x); // (1)
|
||||
* a = s => Sink(s); // (2)
|
||||
* a(x); // (3)
|
||||
* }
|
||||
*
|
||||
* void Bar()
|
||||
* {
|
||||
* Foo(s => Sink(s)); // (4)
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If a source call context flow feature is used, `a` can be assigned a special
|
||||
* type that is incompatible with the type of _any_ lambda expression, which will
|
||||
* prevent the call edge from (1) to (4). Note that the call edge from (3) to (2)
|
||||
* will still be valid.
|
||||
*/
|
||||
default DataFlowType getSourceContextParameterNodeType(Node p) { none() }
|
||||
|
||||
predicate nodeIsHidden(Node node);
|
||||
|
||||
class DataFlowExpr;
|
||||
|
||||
@@ -1103,16 +1103,6 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
private module FwdTypeFlowInput implements TypeFlowInput {
|
||||
predicate enableTypeFlow = Param::enableTypeFlow/0;
|
||||
|
||||
pragma[nomagic]
|
||||
predicate isParameterNodeInSourceCallContext(ParamNode p) {
|
||||
hasSourceCallCtx() and
|
||||
exists(Node source, DataFlowCallable c |
|
||||
Config::isSource(pragma[only_bind_into](source), _) and
|
||||
nodeEnclosingCallable(source, c) and
|
||||
nodeEnclosingCallable(p, c)
|
||||
)
|
||||
}
|
||||
|
||||
predicate relevantCallEdgeIn = PrevStage::relevantCallEdgeIn/2;
|
||||
|
||||
predicate relevantCallEdgeOut = PrevStage::relevantCallEdgeOut/2;
|
||||
@@ -1420,8 +1410,6 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
private module RevTypeFlowInput implements TypeFlowInput {
|
||||
predicate enableTypeFlow = Param::enableTypeFlow/0;
|
||||
|
||||
predicate isParameterNodeInSourceCallContext(ParamNode p) { none() }
|
||||
|
||||
predicate relevantCallEdgeIn(Call call, Callable c) {
|
||||
flowOutOfCallAp(call, c, _, _, _, _, _)
|
||||
}
|
||||
|
||||
@@ -1893,9 +1893,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
signature module TypeFlowInput {
|
||||
predicate enableTypeFlow();
|
||||
|
||||
/** Holds if `p` is a parameter of a callable with a source node that has a call context. */
|
||||
predicate isParameterNodeInSourceCallContext(ParamNode p);
|
||||
|
||||
/** Holds if the edge is possibly needed in the direction `call` to `c`. */
|
||||
predicate relevantCallEdgeIn(Call call, Callable c);
|
||||
|
||||
@@ -1956,9 +1953,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
/**
|
||||
* Holds if a sequence of calls may propagate the value of `arg` to some
|
||||
* argument-to-parameter call edge that strengthens the static type.
|
||||
*
|
||||
* This predicate is a reverse flow computation, starting at calls that
|
||||
* strengthen the type and then following relevant call edges backwards.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate trackedArgTypeCand(ArgNode arg) {
|
||||
@@ -1993,9 +1987,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
* Holds if `p` is part of a value-propagating call path where the
|
||||
* end-points have stronger types than the intermediate parameter and
|
||||
* argument nodes.
|
||||
*
|
||||
* This predicate is a forward flow computation, intersecting with the
|
||||
* reverse flow computation done in `trackedArgTypeCand`.
|
||||
*/
|
||||
private predicate trackedParamType(ParamNode p) {
|
||||
exists(Call call1, Callable c1, ArgNode argOut, Call call2, Callable c2, ArgNode argIn |
|
||||
@@ -2022,8 +2013,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
typeStrongerThanFilter(at, pt)
|
||||
)
|
||||
or
|
||||
Input::isParameterNodeInSourceCallContext(p)
|
||||
or
|
||||
exists(ArgNode arg |
|
||||
trackedArgType(arg) and
|
||||
relevantCallEdge(_, _, arg, p) and
|
||||
@@ -2115,12 +2104,8 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
* context.
|
||||
*/
|
||||
private predicate typeFlowParamType(ParamNode p, Type t, boolean cc) {
|
||||
exists(Callable c | Input::dataFlowNonCallEntry(c, cc) |
|
||||
cc = true and
|
||||
nodeEnclosingCallable(p, c) and
|
||||
t = getSourceContextParameterNodeType(p)
|
||||
or
|
||||
(cc = false or not exists(getSourceContextParameterNodeType(p))) and
|
||||
exists(Callable c |
|
||||
Input::dataFlowNonCallEntry(c, cc) and
|
||||
trackedParamWithType(p, t, c)
|
||||
)
|
||||
or
|
||||
|
||||
Reference in New Issue
Block a user