Merge branch 'main' into scinit

This commit is contained in:
Geoffrey White
2025-08-19 08:50:12 +01:00
612 changed files with 15548 additions and 8566 deletions

View File

@@ -30,6 +30,13 @@ common --registry=https://bcr.bazel.build
common --@rules_dotnet//dotnet/settings:strict_deps=false
# we only configure a nightly toolchain
common --@rules_rust//rust/toolchain/channel=nightly
# rust does not like the gold linker, while bazel does by default, so let's avoid using it
common:linux --linkopt=-fuse-ld=lld
common:macos --linkopt=-fuse-ld=lld
# Reduce this eventually to empty, once we've fixed all our usages of java, and https://github.com/bazel-contrib/rules_go/issues/4193 is fixed
common --incompatible_autoload_externally="+@rules_java,+@rules_shell"

View File

@@ -15,7 +15,7 @@ local_path_override(
# see https://registry.bazel.build/ for a list of available packages
bazel_dep(name = "platforms", version = "0.0.11")
bazel_dep(name = "rules_go", version = "0.50.1")
bazel_dep(name = "rules_go", version = "0.56.1")
bazel_dep(name = "rules_pkg", version = "1.0.1")
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
bazel_dep(name = "rules_python", version = "0.40.0")
@@ -28,7 +28,7 @@ bazel_dep(name = "rules_kotlin", version = "2.1.3-codeql.1")
bazel_dep(name = "gazelle", version = "0.40.0")
bazel_dep(name = "rules_dotnet", version = "0.17.4")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "rules_rust", version = "0.58.0")
bazel_dep(name = "rules_rust", version = "0.63.0")
bazel_dep(name = "zstd", version = "1.5.5.bcr.1")
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
@@ -38,7 +38,10 @@ bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True
RUST_EDITION = "2024"
# run buildutils-internal/scripts/fill-rust-sha256s.py when updating (internal repo)
RUST_VERSION = "1.86.0"
# a nightly toolchain is required to enable experimental_use_cc_common_link, which we require internally
# we prefer to run the same version as internally, even if experimental_use_cc_common_link is not really
# required in this repo
RUST_VERSION = "nightly/2025-08-01"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
@@ -50,26 +53,26 @@ rust.toolchain(
],
# generated by buildutils-internal/scripts/fill-rust-sha256s.py (internal repo)
sha256s = {
"rustc-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "4438b809ce4a083af31ed17aeeedcc8fc60ccffc0625bef1926620751b6989d7",
"rustc-1.86.0-x86_64-apple-darwin.tar.xz": "42b76253626febb7912541a30d3379f463dec89581aad4cb72c6c04fb5a71dc5",
"rustc-1.86.0-aarch64-apple-darwin.tar.xz": "23b8f52102249a47ab5bc859d54c9a3cb588a3259ba3f00f557d50edeca4fde9",
"rustc-1.86.0-x86_64-pc-windows-msvc.tar.xz": "fdde839fea274529a31e51eb85c6df1782cc8479c9d1bc24e2914d66a0de41ab",
"clippy-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "02aaff2c1407d2da8dba19aa4970dd873e311902b120a66cbcdbe51eb8836edf",
"clippy-1.86.0-x86_64-apple-darwin.tar.xz": "bb85efda7bbffaf124867f5ca36d50932b1e8f533c62ee923438afb32ff8fe9a",
"clippy-1.86.0-aarch64-apple-darwin.tar.xz": "239fa3a604b124f0312f2af08537874a1227dba63385484b468cca62e7c4f2f2",
"clippy-1.86.0-x86_64-pc-windows-msvc.tar.xz": "d00498f47d49219f032e2c5eeebdfc3d32317c0dc3d3fd7125327445bc482cb4",
"cargo-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "c5c1590f7e9246ad9f4f97cfe26ffa92707b52a769726596a9ef81565ebd908b",
"cargo-1.86.0-x86_64-apple-darwin.tar.xz": "af163eb02d1a178044d1b4f2375960efd47130f795f6e33d09e345454bb26f4e",
"cargo-1.86.0-aarch64-apple-darwin.tar.xz": "3cb13873d48c3e1e4cc684d42c245226a11fba52af6b047c3346ed654e7a05c0",
"cargo-1.86.0-x86_64-pc-windows-msvc.tar.xz": "e57a9d89619b5604899bac443e68927bdd371e40f2e03e18950b6ceb3eb67966",
"llvm-tools-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "282145ab7a63c98b625856f44b905b4dc726b497246b824632a5790debe95a78",
"llvm-tools-1.86.0-x86_64-apple-darwin.tar.xz": "b55706e92f7da989207c50c13c7add483a9fedd233bc431b106eca2a8f151ec9",
"llvm-tools-1.86.0-aarch64-apple-darwin.tar.xz": "04d3618c686845853585f036e3211eb9e18f2d290f4610a7a78bdc1fcce1ebd9",
"llvm-tools-1.86.0-x86_64-pc-windows-msvc.tar.xz": "721a17cc8dc219177e4277a3592253934ef08daa1e1b12eda669a67d15fad8dd",
"rust-std-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "67be7184ea388d8ce0feaf7fdea46f1775cfc2970930264343b3089898501d37",
"rust-std-1.86.0-x86_64-apple-darwin.tar.xz": "3b1140d54870a080080e84700143f4a342fbd02a410a319b05d9c02e7dcf44cc",
"rust-std-1.86.0-aarch64-apple-darwin.tar.xz": "0fb121fb3b8fa9027d79ff598500a7e5cd086ddbc3557482ed3fdda00832c61b",
"rust-std-1.86.0-x86_64-pc-windows-msvc.tar.xz": "3d5354b7b9cb950b58bff3fce18a652aa374bb30c8f70caebd3bd0b43cb41a33",
"2025-08-01/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "9bbeaf5d3fc7247d31463a9083aa251c995cc50662c8219e7a2254d76a72a9a4",
"2025-08-01/rustc-nightly-x86_64-apple-darwin.tar.xz": "c9ea539a8eff0d5d162701f99f9e1aabe14dd0dfb420d62362817a5d09219de7",
"2025-08-01/rustc-nightly-aarch64-apple-darwin.tar.xz": "ae83feebbc39cfd982e4ecc8297731fe79c185173aee138467b334c5404b3773",
"2025-08-01/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "9f170c30d802a349be60cf52ec46260802093cb1013ad667fc0d528b7b10152f",
"2025-08-01/clippy-nightly-x86_64-unknown-linux-gnu.tar.xz": "9ae5f3cd8f557c4f6df522597c69d14398cf604cfaed2b83e767c4b77a7eaaf6",
"2025-08-01/clippy-nightly-x86_64-apple-darwin.tar.xz": "983cb9ee0b6b968188e04ab2d33743d54764b2681ce565e1b3f2b9135c696a3e",
"2025-08-01/clippy-nightly-aarch64-apple-darwin.tar.xz": "ed2219dbc49d088225e1b7c5c4390fa295066e071fddaa2714018f6bb39ddbf0",
"2025-08-01/clippy-nightly-x86_64-pc-windows-msvc.tar.xz": "911f40ab5cbdd686f40e00965271fe47c4805513a308ed01f30eafb25b448a50",
"2025-08-01/cargo-nightly-x86_64-unknown-linux-gnu.tar.xz": "106463c284e48e4904c717471eeec2be5cc83a9d2cae8d6e948b52438cad2e69",
"2025-08-01/cargo-nightly-x86_64-apple-darwin.tar.xz": "6ad35c40efc41a8c531ea43235058347b6902d98a9693bf0aed7fc16d5590cef",
"2025-08-01/cargo-nightly-aarch64-apple-darwin.tar.xz": "dd28c365e9d298abc3154c797720ad36a0058f131265c9978b4c8e4e37012c8a",
"2025-08-01/cargo-nightly-x86_64-pc-windows-msvc.tar.xz": "7b431286e12d6b3834b038f078389a00cac73f351e8c3152b2504a3c06420b3b",
"2025-08-01/llvm-tools-nightly-x86_64-unknown-linux-gnu.tar.xz": "e342e305d7927cc288d386983b2bc253cfad3776b113386e903d0b302648ef47",
"2025-08-01/llvm-tools-nightly-x86_64-apple-darwin.tar.xz": "e44dd3506524d85c37b3a54bcc91d01378fd2c590b2db5c5974d12f05c1b84d1",
"2025-08-01/llvm-tools-nightly-aarch64-apple-darwin.tar.xz": "0c1b5f46dd81be4a9227b10283a0fcaa39c14fea7e81aea6fd6d9887ff6cdc41",
"2025-08-01/llvm-tools-nightly-x86_64-pc-windows-msvc.tar.xz": "423e5fd11406adccbc31b8456ceb7375ce055cdf45e90d2c3babeb2d7f58383f",
"2025-08-01/rust-std-nightly-x86_64-unknown-linux-gnu.tar.xz": "3c0ceb46a252647a1d4c7116d9ccae684fa5e42aaf3296419febd2c962c3b41d",
"2025-08-01/rust-std-nightly-x86_64-apple-darwin.tar.xz": "3be416003cab10f767390a753d1d16ae4d26c7421c03c98992cf1943e5b0efe8",
"2025-08-01/rust-std-nightly-aarch64-apple-darwin.tar.xz": "4046ac0ef951cb056b5028a399124f60999fa37792eab69d008d8d7965f389b4",
"2025-08-01/rust-std-nightly-x86_64-pc-windows-msvc.tar.xz": "191ed9d8603c3a4fe5a7bbbc2feb72049078dae2df3d3b7d5dedf3abbf823e6e",
},
versions = [RUST_VERSION],
)
@@ -260,7 +263,7 @@ use_repo(
)
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.24.0")
go_sdk.download(version = "1.25.0")
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//go/extractor:go.mod")

View File

@@ -1,6 +1,7 @@
private import actions
private import codeql.actions.TaintTracking
private import codeql.actions.dataflow.ExternalFlow
private import codeql.actions.security.ControlChecks
import codeql.actions.dataflow.FlowSources
import codeql.actions.DataFlow
@@ -65,6 +66,16 @@ class ArgumentInjectionFromMaDSink extends ArgumentInjectionSink {
override string getCommand() { result = "unknown" }
}
/**
* Gets the event that is relevant for the given node in the context of argument injection.
*
* This is used to highlight the event in the query results when an alert is raised.
*/
Event getRelevantEventInPrivilegedContext(DataFlow::Node node) {
inPrivilegedContext(node.asExpr(), result) and
not exists(ControlCheck check | check.protects(node.asExpr(), result, "argument-injection"))
}
/**
* A taint-tracking configuration for unsafe user input
* that is used to construct and evaluate a code script.
@@ -88,6 +99,16 @@ private module ArgumentInjectionConfig implements DataFlow::ConfigSig {
run.getScript().getAnEnvReachingArgumentInjectionSink(var, _, _)
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
result = getRelevantEventInPrivilegedContext(sink).getLocation()
}
}
/** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */

View File

@@ -4,6 +4,7 @@ import codeql.actions.DataFlow
import codeql.actions.dataflow.FlowSources
import codeql.actions.security.PoisonableSteps
import codeql.actions.security.UntrustedCheckoutQuery
import codeql.actions.security.ControlChecks
string unzipRegexp() { result = "(unzip|tar)\\s+.*" }
@@ -292,6 +293,16 @@ class ArtifactPoisoningSink extends DataFlow::Node {
string getPath() { result = download.getPath() }
}
/**
* Gets the event that is relevant for the given node in the context of artifact poisoning.
*
* This is used to highlight the event in the query results when an alert is raised.
*/
Event getRelevantEventInPrivilegedContext(DataFlow::Node node) {
inPrivilegedContext(node.asExpr(), result) and
not exists(ControlCheck check | check.protects(node.asExpr(), result, "artifact-poisoning"))
}
/**
* A taint-tracking configuration for unsafe artifacts
* that is used may lead to artifact poisoning
@@ -318,6 +329,16 @@ private module ArtifactPoisoningConfig implements DataFlow::ConfigSig {
exists(run.getScript().getAFileReadCommand())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
result = getRelevantEventInPrivilegedContext(sink).getLocation()
}
}
/** Tracks flow of unsafe artifacts that is used in an insecure way. */

View File

@@ -3,6 +3,8 @@ private import codeql.actions.TaintTracking
private import codeql.actions.dataflow.ExternalFlow
import codeql.actions.dataflow.FlowSources
import codeql.actions.DataFlow
import codeql.actions.security.ControlChecks
import codeql.actions.security.CachePoisoningQuery
class CodeInjectionSink extends DataFlow::Node {
CodeInjectionSink() {
@@ -11,6 +13,46 @@ class CodeInjectionSink extends DataFlow::Node {
}
}
/**
* Get the relevant event for the sink in CodeInjectionCritical.ql.
*/
Event getRelevantCriticalEventForSink(DataFlow::Node sink) {
inPrivilegedContext(sink.asExpr(), result) and
not exists(ControlCheck check | check.protects(sink.asExpr(), result, "code-injection")) and
// exclude cases where the sink is a JS script and the expression uses toJson
not exists(UsesStep script |
script.getCallee() = "actions/github-script" and
script.getArgumentExpr("script") = sink.asExpr() and
exists(getAToJsonReferenceExpression(sink.asExpr().(Expression).getExpression(), _))
)
}
/**
* Get the relevant event for the sink in CachePoisoningViaCodeInjection.ql.
*/
Event getRelevantCachePoisoningEventForSink(DataFlow::Node sink) {
exists(LocalJob job |
job = sink.asExpr().getEnclosingJob() and
job.getATriggerEvent() = result and
// job can be triggered by an external user
result.isExternallyTriggerable() and
// excluding privileged workflows since they can be exploited in easier circumstances
// which is covered by `actions/code-injection/critical`
not job.isPrivilegedExternallyTriggerable(result) and
(
// the workflow runs in the context of the default branch
runsOnDefaultBranch(result)
or
// the workflow caller runs in the context of the default branch
result.getName() = "workflow_call" and
exists(ExternalJob caller |
caller.getCallee() = job.getLocation().getFile().getRelativePath() and
runsOnDefaultBranch(caller.getATriggerEvent())
)
)
)
}
/**
* A taint-tracking configuration for unsafe user input
* that is used to construct and evaluate a code script.
@@ -35,6 +77,18 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig {
exists(run.getScript().getAFileReadCommand())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
result = getRelevantCriticalEventForSink(sink).getLocation()
or
result = getRelevantCachePoisoningEventForSink(sink).getLocation()
}
}
/** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */

View File

@@ -3,11 +3,20 @@ private import codeql.actions.TaintTracking
private import codeql.actions.dataflow.ExternalFlow
import codeql.actions.dataflow.FlowSources
import codeql.actions.DataFlow
import codeql.actions.security.ControlChecks
private class CommandInjectionSink extends DataFlow::Node {
CommandInjectionSink() { madSink(this, "command-injection") }
}
/** Get the relevant event for the sink in CommandInjectionCritical.ql. */
Event getRelevantEventInPrivilegedContext(DataFlow::Node sink) {
inPrivilegedContext(sink.asExpr(), result) and
not exists(ControlCheck check |
check.protects(sink.asExpr(), result, ["command-injection", "code-injection"])
)
}
/**
* A taint-tracking configuration for unsafe user input
* that is used to construct and evaluate a system command.
@@ -16,6 +25,16 @@ private module CommandInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) { sink instanceof CommandInjectionSink }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
result = getRelevantEventInPrivilegedContext(sink).getLocation()
}
}
/** Tracks flow of unsafe user input that is used to construct and evaluate a system command. */

View File

@@ -72,6 +72,25 @@ class EnvPathInjectionFromMaDSink extends EnvPathInjectionSink {
EnvPathInjectionFromMaDSink() { madSink(this, "envpath-injection") }
}
/**
* Get the relevant event for a sink in EnvPathInjectionCritical.ql where the source type is "artifact".
*/
Event getRelevantArtifactEventInPrivilegedContext(DataFlow::Node sink) {
inPrivilegedContext(sink.asExpr(), result) and
not exists(ControlCheck check |
check.protects(sink.asExpr(), result, ["untrusted-checkout", "artifact-poisoning"])
) and
sink instanceof EnvPathInjectionFromFileReadSink
}
/**
* Get the relevant event for a sink in EnvPathInjectionCritical.ql where the source type is not "artifact".
*/
Event getRelevantNonArtifactEventInPrivilegedContext(DataFlow::Node sink) {
inPrivilegedContext(sink.asExpr(), result) and
not exists(ControlCheck check | check.protects(sink.asExpr(), result, "code-injection"))
}
/**
* A taint-tracking configuration for unsafe user input
* that is used to construct and evaluate an environment variable.
@@ -108,6 +127,18 @@ private module EnvPathInjectionConfig implements DataFlow::ConfigSig {
exists(run.getScript().getAFileReadCommand())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
result = getRelevantArtifactEventInPrivilegedContext(sink).getLocation()
or
result = getRelevantNonArtifactEventInPrivilegedContext(sink).getLocation()
}
}
/** Tracks flow of unsafe user input that is used to construct and evaluate the PATH environment variable. */

View File

@@ -126,6 +126,32 @@ class EnvVarInjectionFromMaDSink extends EnvVarInjectionSink {
EnvVarInjectionFromMaDSink() { madSink(this, "envvar-injection") }
}
/**
* Get the relevant event for a sink in EnvVarInjectionCritical.ql where the source type is "artifact".
*/
Event getRelevantArtifactEventInPrivilegedContext(DataFlow::Node sink) {
inPrivilegedContext(sink.asExpr(), result) and
not exists(ControlCheck check |
check
.protects(sink.asExpr(), result,
["envvar-injection", "untrusted-checkout", "artifact-poisoning"])
) and
(
sink instanceof EnvVarInjectionFromFileReadSink or
madSink(sink, "envvar-injection")
)
}
/**
* Get the relevant event for a sink in EnvVarInjectionCritical.ql where the source type is not "artifact".
*/
Event getRelevantNonArtifactEventInPrivilegedContext(DataFlow::Node sink) {
inPrivilegedContext(sink.asExpr(), result) and
not exists(ControlCheck check |
check.protects(sink.asExpr(), result, ["envvar-injection", "code-injection"])
)
}
/**
* A taint-tracking configuration for unsafe user input
* that is used to construct and evaluate an environment variable.
@@ -163,6 +189,18 @@ private module EnvVarInjectionConfig implements DataFlow::ConfigSig {
exists(run.getScript().getAFileReadCommand())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
result = getRelevantArtifactEventInPrivilegedContext(sink).getLocation()
or
result = getRelevantNonArtifactEventInPrivilegedContext(sink).getLocation()
}
}
/** Tracks flow of unsafe user input that is used to construct and evaluate an environment variable. */

View File

@@ -21,18 +21,12 @@ import codeql.actions.security.ControlChecks
from EnvPathInjectionFlow::PathNode source, EnvPathInjectionFlow::PathNode sink, Event event
where
EnvPathInjectionFlow::flowPath(source, sink) and
inPrivilegedContext(sink.getNode().asExpr(), event) and
(
not source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, "code-injection")
)
event = getRelevantNonArtifactEventInPrivilegedContext(sink.getNode())
or
source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, ["untrusted-checkout", "artifact-poisoning"])
) and
sink.getNode() instanceof EnvPathInjectionFromFileReadSink
event = getRelevantArtifactEventInPrivilegedContext(sink.getNode())
)
select sink.getNode(), source, sink,
"Potential PATH environment variable injection in $@, which may be controlled by an external user ($@).",

View File

@@ -22,26 +22,15 @@ import codeql.actions.security.ControlChecks
from EnvVarInjectionFlow::PathNode source, EnvVarInjectionFlow::PathNode sink, Event event
where
EnvVarInjectionFlow::flowPath(source, sink) and
inPrivilegedContext(sink.getNode().asExpr(), event) and
// exclude paths to file read sinks from non-artifact sources
(
// source is text
not source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, ["envvar-injection", "code-injection"])
)
event = getRelevantNonArtifactEventInPrivilegedContext(sink.getNode())
or
// source is an artifact or a file from an untrusted checkout
source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
not exists(ControlCheck check |
check
.protects(sink.getNode().asExpr(), event,
["envvar-injection", "untrusted-checkout", "artifact-poisoning"])
) and
(
sink.getNode() instanceof EnvVarInjectionFromFileReadSink or
madSink(sink.getNode(), "envvar-injection")
)
event = getRelevantArtifactEventInPrivilegedContext(sink.getNode())
)
select sink.getNode(), source, sink,
"Potential environment variable injection in $@, which may be controlled by an external user ($@).",

View File

@@ -22,15 +22,8 @@ import codeql.actions.security.ControlChecks
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, Event event
where
CodeInjectionFlow::flowPath(source, sink) and
inPrivilegedContext(sink.getNode().asExpr(), event) and
source.getNode().(RemoteFlowSource).getEventName() = event.getName() and
not exists(ControlCheck check | check.protects(sink.getNode().asExpr(), event, "code-injection")) and
// exclude cases where the sink is a JS script and the expression uses toJson
not exists(UsesStep script |
script.getCallee() = "actions/github-script" and
script.getArgumentExpr("script") = sink.getNode().asExpr() and
exists(getAToJsonReferenceExpression(sink.getNode().asExpr().(Expression).getExpression(), _))
)
event = getRelevantCriticalEventForSink(sink.getNode()) and
source.getNode().(RemoteFlowSource).getEventName() = event.getName()
select sink.getNode(), source, sink,
"Potential code injection in $@, which may be controlled by an external user ($@).", sink,
sink.getNode().asExpr().(Expression).getRawExpression(), event, event.getName()

View File

@@ -18,30 +18,13 @@ import codeql.actions.security.CachePoisoningQuery
import CodeInjectionFlow::PathGraph
import codeql.actions.security.ControlChecks
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, LocalJob job, Event event
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, Event event
where
CodeInjectionFlow::flowPath(source, sink) and
job = sink.getNode().asExpr().getEnclosingJob() and
job.getATriggerEvent() = event and
// job can be triggered by an external user
event.isExternallyTriggerable() and
event = getRelevantCachePoisoningEventForSink(sink.getNode()) and
// the checkout is not controlled by an access check
not exists(ControlCheck check |
check.protects(source.getNode().asExpr(), event, "code-injection")
) and
// excluding privileged workflows since they can be exploited in easier circumstances
// which is covered by `actions/code-injection/critical`
not job.isPrivilegedExternallyTriggerable(event) and
(
// the workflow runs in the context of the default branch
runsOnDefaultBranch(event)
or
// the workflow caller runs in the context of the default branch
event.getName() = "workflow_call" and
exists(ExternalJob caller |
caller.getCallee() = job.getLocation().getFile().getRelativePath() and
runsOnDefaultBranch(caller.getATriggerEvent())
)
)
select sink.getNode(), source, sink,
"Unprivileged code injection in $@, which may lead to cache poisoning ($@).", sink,

View File

@@ -19,10 +19,7 @@ import codeql.actions.security.ControlChecks
from ArtifactPoisoningFlow::PathNode source, ArtifactPoisoningFlow::PathNode sink, Event event
where
ArtifactPoisoningFlow::flowPath(source, sink) and
inPrivilegedContext(sink.getNode().asExpr(), event) and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, "artifact-poisoning")
)
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()

View File

@@ -21,10 +21,7 @@ import codeql.actions.security.ControlChecks
from CommandInjectionFlow::PathNode source, CommandInjectionFlow::PathNode sink, Event event
where
CommandInjectionFlow::flowPath(source, sink) and
inPrivilegedContext(sink.getNode().asExpr(), event) and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, ["command-injection", "code-injection"])
)
event = getRelevantEventInPrivilegedContext(sink.getNode())
select sink.getNode(), source, sink,
"Potential command injection in $@, which may be controlled by an external user ($@).", sink,
sink.getNode().asExpr().(Expression).getRawExpression(), event, event.getName()

View File

@@ -20,10 +20,7 @@ import codeql.actions.security.ControlChecks
from ArgumentInjectionFlow::PathNode source, ArgumentInjectionFlow::PathNode sink, Event event
where
ArgumentInjectionFlow::flowPath(source, sink) and
inPrivilegedContext(sink.getNode().asExpr(), event) and
not exists(ControlCheck check |
check.protects(sink.getNode().asExpr(), event, "argument-injection")
)
event = getRelevantEventInPrivilegedContext(sink.getNode())
select sink.getNode(), source, sink,
"Potential argument injection in $@ command, which may be controlled by an external user ($@).",
sink, sink.getNode().(ArgumentInjectionSink).getCommand(), event, event.getName()

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The guards libraries (`semmle.code.cpp.controlflow.Guards` and `semmle.code.cpp.controlflow.IRGuards`) have been improved to recognize more guards.

View File

@@ -936,6 +936,77 @@ private module Cached {
ValueNumber getUnary() { result.getAnInstruction() = instr.getUnary() }
}
signature predicate sinkSig(Instruction instr);
private module BooleanInstruction<sinkSig/1 isSink> {
/**
* Holds if `i1` flows to `i2` in a single step and `i2` is not an
* instruction that produces a value of Boolean type.
*/
private predicate stepToNonBoolean(Instruction i1, Instruction i2) {
not i2.getResultIRType() instanceof IRBooleanType and
(
i2.(CopyInstruction).getSourceValue() = i1
or
i2.(ConvertInstruction).getUnary() = i1
or
i2.(BuiltinExpectCallInstruction).getArgument(0) = i1
)
}
private predicate rev(Instruction instr) {
isSink(instr)
or
exists(Instruction instr1 |
rev(instr1) and
stepToNonBoolean(instr, instr1)
)
}
private predicate hasBooleanType(Instruction instr) {
instr.getResultIRType() instanceof IRBooleanType
}
private predicate fwd(Instruction instr) {
rev(instr) and
(
hasBooleanType(instr)
or
exists(Instruction instr0 |
fwd(instr0) and
stepToNonBoolean(instr0, instr)
)
)
}
private predicate prunedStep(Instruction i1, Instruction i2) {
fwd(i1) and
fwd(i2) and
stepToNonBoolean(i1, i2)
}
private predicate stepsPlus(Instruction i1, Instruction i2) =
doublyBoundedFastTC(prunedStep/2, hasBooleanType/1, isSink/1)(i1, i2)
/**
* Gets the Boolean-typed instruction that defines `instr` before any
* integer conversions are applied, if any.
*/
Instruction get(Instruction instr) {
isSink(instr) and
(
result = instr
or
stepsPlus(result, instr)
) and
hasBooleanType(result)
}
}
private predicate isUnaryComparesEqLeft(Instruction instr) {
unary_compares_eq(_, instr.getAUse(), 0, _, _)
}
/**
* Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`.
*
@@ -966,14 +1037,19 @@ private module Cached {
)
or
compares_eq(test.(BuiltinExpectCallValueNumber).getCondition(), left, right, k, areEqual, value)
}
private predicate isConvertedBool(Instruction instr) {
instr.getResultIRType() instanceof IRBooleanType
or
isConvertedBool(instr.(ConvertInstruction).getUnary())
or
isConvertedBool(instr.(BuiltinExpectCallInstruction).getCondition())
exists(Operand l, BooleanValue bv |
// 1. test = value -> int(l) = 0 is !bv
unary_compares_eq(test, l, 0, bv.getValue().booleanNot(), value) and
// 2. l = bv -> left + right is areEqual
compares_eq(valueNumber(BooleanInstruction<isUnaryComparesEqLeft/1>::get(l.getDef())), left,
right, k, areEqual, bv)
// We want this to hold:
// `test = value -> left + right is areEqual`
// Applying 2 we need to show:
// `test = value -> l = bv`
// And `l = bv` holds by `int(l) = 0 is !bv`
)
}
/**
@@ -1006,19 +1082,11 @@ private module Cached {
k = k1 + k2
)
or
exists(CompareValueNumber cmp, Operand left, Operand right, AbstractValue v |
test = cmp and
pragma[only_bind_into](cmp)
.hasOperands(pragma[only_bind_into](left), pragma[only_bind_into](right)) and
isConvertedBool(left.getDef()) and
int_value(right.getDef()) = 0 and
unary_compares_eq(valueNumberOfOperand(left), op, k, areEqual, v)
|
cmp instanceof CompareNEValueNumber and
v = value
or
cmp instanceof CompareEQValueNumber and
v.getDualValue() = value
// See argument for why this is correct in compares_eq
exists(Operand l, BooleanValue bv |
unary_compares_eq(test, l, 0, bv.getValue().booleanNot(), value) and
unary_compares_eq(valueNumber(BooleanInstruction<isUnaryComparesEqLeft/1>::get(l.getDef())),
op, k, areEqual, bv)
)
or
unary_compares_eq(test.(BuiltinExpectCallValueNumber).getCondition(), op, k, areEqual, value)
@@ -1116,70 +1184,26 @@ private module Cached {
)
}
private predicate isBuiltInExpectArg(Instruction instr) {
instr = any(BuiltinExpectCallInstruction buildinExpect).getArgument(0)
}
/** A call to the builtin operation `__builtin_expect`. */
private class BuiltinExpectCallInstruction extends CallInstruction {
BuiltinExpectCallInstruction() { this.getStaticCallTarget().hasName("__builtin_expect") }
/** Gets the condition of this call. */
Instruction getCondition() { result = this.getConditionOperand().getDef() }
Operand getConditionOperand() {
// The first parameter of `__builtin_expect` has type `long`. So we skip
// the conversion when inferring guards.
result = this.getArgument(0).(ConvertInstruction).getUnaryOperand()
Instruction getCondition() {
result = BooleanInstruction<isBuiltInExpectArg/1>::get(this.getArgument(0))
}
}
/**
* Holds if `left == right + k` is `areEqual` if `cmp` evaluates to `value`,
* and `cmp` is an instruction that compares the value of
* `__builtin_expect(left == right + k, _)` to `0`.
*/
private predicate builtin_expect_eq(
CompareValueNumber cmp, Operand left, Operand right, int k, boolean areEqual,
AbstractValue value
) {
exists(BuiltinExpectCallValueNumber call, Instruction const, AbstractValue innerValue |
int_value(const) = 0 and
cmp.hasOperands(call.getAUse(), const.getAUse()) and
compares_eq(call.getCondition(), left, right, k, areEqual, innerValue)
|
cmp instanceof CompareNEValueNumber and
value = innerValue
or
cmp instanceof CompareEQValueNumber and
value.getDualValue() = innerValue
)
}
private predicate complex_eq(
ValueNumber cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
) {
sub_eq(cmp, left, right, k, areEqual, value)
or
add_eq(cmp, left, right, k, areEqual, value)
or
builtin_expect_eq(cmp, left, right, k, areEqual, value)
}
/**
* Holds if `op == k` is `areEqual` if `cmp` evaluates to `value`, and `cmp` is
* an instruction that compares the value of `__builtin_expect(op == k, _)` to `0`.
*/
private predicate unary_builtin_expect_eq(
CompareValueNumber cmp, Operand op, int k, boolean areEqual, AbstractValue value
) {
exists(BuiltinExpectCallValueNumber call, Instruction const, AbstractValue innerValue |
int_value(const) = 0 and
cmp.hasOperands(call.getAUse(), const.getAUse()) and
unary_compares_eq(call.getCondition(), op, k, areEqual, innerValue)
|
cmp instanceof CompareNEValueNumber and
value = innerValue
or
cmp instanceof CompareEQValueNumber and
value.getDualValue() = innerValue
)
}
private predicate unary_complex_eq(
@@ -1188,8 +1212,6 @@ private module Cached {
unary_sub_eq(test, op, k, areEqual, value)
or
unary_add_eq(test, op, k, areEqual, value)
or
unary_builtin_expect_eq(test, op, k, areEqual, value)
}
/*
@@ -1215,6 +1237,15 @@ private module Cached {
exists(AbstractValue dual | value = dual.getDualValue() |
compares_lt(test.(LogicalNotValueNumber).getUnary(), left, right, k, isLt, dual)
)
or
compares_lt(test.(BuiltinExpectCallValueNumber).getCondition(), left, right, k, isLt, value)
or
// See argument for why this is correct in compares_eq
exists(Operand l, BooleanValue bv |
unary_compares_eq(test, l, 0, bv.getValue().booleanNot(), value) and
compares_lt(valueNumber(BooleanInstruction<isUnaryComparesEqLeft/1>::get(l.getDef())), left,
right, k, isLt, bv)
)
}
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
@@ -1234,6 +1265,15 @@ private module Cached {
int_value(const) = k1 and
k = k1 + k2
)
or
compares_lt(test.(BuiltinExpectCallValueNumber).getCondition(), op, k, isLt, value)
or
// See argument for why this is correct in compares_eq
exists(Operand l, BooleanValue bv |
unary_compares_eq(test, l, 0, bv.getValue().booleanNot(), value) and
compares_lt(valueNumber(BooleanInstruction<isUnaryComparesEqLeft/1>::get(l.getDef())), op, k,
isLt, bv)
)
}
/** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */

View File

@@ -14,6 +14,9 @@ import semmle.code.cpp.ConfigurationTestFile
from GlobalVariable gv
where
gv.getName().length() <= 3 and
// We will give an alert for the TemplateVariable, so we don't
// need to also give one for each instantiation
not gv instanceof VariableTemplateInstantiation and
not gv.isStatic() and
not gv.getFile() instanceof ConfigurationTestFile // variables in files generated during configuration are likely false positives
select gv,

View File

@@ -82,6 +82,16 @@ module OverflowDestinationConfig implements DataFlow::ConfigSig {
nodeIsBarrierEqualityCandidate(node, access, checkedVar)
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(FunctionCall fc | result = fc.getLocation() |
sourceSized(fc, sink.asIndirectConvertedExpr())
)
}
}
module OverflowDestination = TaintTracking::Global<OverflowDestinationConfig>;

View File

@@ -168,6 +168,19 @@ module NonConstFlowConfig implements DataFlow::ConfigSig {
cannotContainString(t)
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
exists(FormattingFunctionCall call, Expr formatString | result = call.getLocation() |
isSinkImpl(sink, formatString) and
call.getArgument(call.getFormatParameterIndex()) = formatString
)
}
}
module NonConstFlow = TaintTracking::Global<NonConstFlowConfig>;

View File

@@ -215,6 +215,10 @@ private module LeapYearCheckConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) {
exists(ChecksForLeapYearFunctionCall fc | sink.asExpr() = fc.getAnArgument())
}
predicate observeDiffInformedIncrementalMode() {
none() // only used negatively in UncheckedLeapYearAfterYearModification.ql
}
}
module LeapYearCheckFlow = DataFlow::Global<LeapYearCheckConfig>;
@@ -285,6 +289,14 @@ private module PossibleYearArithmeticOperationCheckConfig implements DataFlow::C
aexpr.getLValue() = fa
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) {
result = source.asExpr().getLocation()
}
Location getASelectedSinkLocation(DataFlow::Node sink) { result = sink.asExpr().getLocation() }
}
module PossibleYearArithmeticOperationCheckFlow =

View File

@@ -93,6 +93,12 @@ module TaintedPathConfig implements DataFlow::ConfigSig {
// make sinks barriers so that we only report the closest instance
isSink(node)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.asIndirectArgument().getLocation()
}
}
module TaintedPath = TaintTracking::Global<TaintedPathConfig>;

View File

@@ -150,6 +150,17 @@ module ExecTaintConfig implements DataFlow::StateConfigSig {
predicate isBarrierOut(DataFlow::Node node) {
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(DataFlow::Node concatResult, Expr command, ExecState state |
result = [concatResult.getLocation(), command.getLocation()] and
isSink(sink, state) and
isSinkImpl(sink, command, _) and
concatResult = state.getOutgoingNode()
)
}
}
module ExecTaint = TaintTracking::GlobalWithState<ExecTaintConfig>;

View File

@@ -39,6 +39,12 @@ module Config implements DataFlow::ConfigSig {
or
node.asCertainDefinition().getUnspecifiedType() instanceof ArithmeticType
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) {
exists(QueryString query | result = query.getLocation() | query = source.asIndirectExpr())
}
}
module Flow = TaintTracking::Global<Config>;

View File

@@ -54,6 +54,12 @@ module SqlTaintedConfig implements DataFlow::ConfigSig {
sql.barrierSqlArgument(input, _)
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(Expr taintedArg | result = taintedArg.getLocation() | taintedArg = asSinkExpr(sink))
}
}
module SqlTainted = TaintTracking::Global<SqlTaintedConfig>;

View File

@@ -124,6 +124,12 @@ module Config implements DataFlow::ConfigSig {
// Block flow if the node is guarded by any <, <= or = operations.
node = DataFlow::BarrierGuard<lessThanOrEqual/3>::getABarrierNode()
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(BufferWrite bw | result = bw.getLocation() | isSink(sink, bw, _))
}
}
module Flow = TaintTracking::Global<Config>;

View File

@@ -43,6 +43,12 @@ private module Config implements DataFlow::ConfigSig {
}
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(VariableAccess va | result = va.getLocation() | isSink(sink, va))
}
}
module Flow = TaintTracking::Global<Config>;

View File

@@ -106,6 +106,12 @@ module Config implements DataFlow::ConfigSig {
not iTo instanceof PointerArithmeticInstruction
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(Expr e | result = e.getLocation() | isSink(sink, _, e))
}
}
module Flow = TaintTracking::Global<Config>;

View File

@@ -120,6 +120,12 @@ module UncontrolledArithConfig implements DataFlow::ConfigSig {
// block unintended flow to pointers
node.asExpr().getUnspecifiedType() instanceof PointerType
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) {
result = getExpr(source).getLocation()
}
}
module UncontrolledArith = TaintTracking::Global<UncontrolledArithConfig>;

View File

@@ -113,6 +113,12 @@ module Config implements DataFlow::ConfigSig {
not iTo instanceof PointerArithmeticInstruction
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(VariableAccess va | result = va.getLocation() | isSink(sink, va, _))
}
}
module Flow = TaintTracking::Global<Config>;

View File

@@ -91,6 +91,12 @@ module TaintedAllocationSizeConfig implements DataFlow::ConfigSig {
// to duplicate results)
any(HeuristicAllocationFunction f).getAParameter() = node.asParameter()
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(Expr alloc | result = alloc.getLocation() | allocSink(alloc, sink))
}
}
module TaintedAllocationSize = TaintTracking::Global<TaintedAllocationSizeConfig>;

View File

@@ -72,6 +72,12 @@ module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSource(source, _) }
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(Expr condition | result = condition.getLocation() | isSink(sink, condition))
}
}
module Flow = TaintTracking::Global<Config>;

View File

@@ -31,6 +31,14 @@ module VerifyResultConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) {
exists(GuardCondition guard | guard.getAChild*() = sink.asExpr())
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(GuardCondition guard | result = guard.getLocation() |
guard.comparesEq(sink.asExpr(), _, 0, false, _)
)
}
}
module VerifyResult = DataFlow::Global<VerifyResultConfig>;

View File

@@ -47,6 +47,12 @@ module ToBufferConfig implements DataFlow::ConfigSig {
}
predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _) }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(SensitiveBufferWrite w | result = w.getLocation() | isSinkImpl(sink, w))
}
}
module ToBufferFlow = TaintTracking::Global<ToBufferConfig>;

View File

@@ -31,6 +31,16 @@ module FromSensitiveConfig implements DataFlow::ConfigSig {
predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sourceNode) {
exists(SensitiveExpr source | result = source.getLocation() | isSourceImpl(sourceNode, source))
}
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(FileWrite w | result = w.getLocation() | isSinkImpl(sink, w, _))
}
}
module FromSensitiveFlow = TaintTracking::Global<FromSensitiveConfig>;

View File

@@ -245,6 +245,14 @@ module FromSensitiveConfig implements DataFlow::ConfigSig {
// sources to not get path duplication.
isSource(node)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(NetworkSendRecv networkSendRecv | result = networkSendRecv.getLocation() |
isSinkSendRecv(sink, networkSendRecv)
)
}
}
module FromSensitiveFlow = TaintTracking::Global<FromSensitiveConfig>;
@@ -266,6 +274,10 @@ module ToEncryptionConfig implements DataFlow::ConfigSig {
// sources to not get path duplication.
isSource(node)
}
predicate observeDiffInformedIncrementalMode() {
none() // only used negatively
}
}
module ToEncryptionFlow = TaintTracking::Global<ToEncryptionConfig>;
@@ -281,6 +293,10 @@ module FromEncryptionConfig implements DataFlow::ConfigSig {
predicate isBarrier(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
predicate observeDiffInformedIncrementalMode() {
none() // only used negatively
}
}
module FromEncryptionFlow = TaintTracking::Global<FromEncryptionConfig>;

View File

@@ -123,6 +123,20 @@ module FromSensitiveConfig implements DataFlow::ConfigSig {
content.(DataFlow::FieldContent).getField() = getRecField(t.stripType())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) {
exists(SensitiveExpr sensitive | result = sensitive.getLocation() |
isSourceImpl(source, sensitive)
)
}
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(SqliteFunctionCall sqliteCall | result = sqliteCall.getLocation() |
isSinkImpl(sink, sqliteCall, _)
)
}
}
module FromSensitiveFlow = TaintTracking::Global<FromSensitiveConfig>;

View File

@@ -87,6 +87,14 @@ module HttpStringToUrlOpenConfig implements DataFlow::ConfigSig {
sink.asIndirectExpr() = fc.getArgument(3)
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) {
result = source.asIndirectExpr().getLocation()
}
Location getASelectedSinkLocation(DataFlow::Node sink) { none() }
}
module HttpStringToUrlOpen = TaintTracking::Global<HttpStringToUrlOpenConfig>;

View File

@@ -44,6 +44,12 @@ module KeyStrengthFlowConfig implements DataFlow::ConfigSig {
exists(getMinimumKeyStrength(name, param))
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(FunctionCall fc | result = fc.getLocation() | sink.asExpr() = fc.getArgument(_))
}
}
module KeyStrengthFlow = DataFlow::Global<KeyStrengthFlowConfig>;

View File

@@ -145,6 +145,18 @@ module Config implements DataFlow::StateConfigSig {
// ```
result instanceof DataFlow::FeatureHasSinkCallContext
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(DataFlow::Node mid, FlowState state | result = mid.getLocation() |
destroyedToBeginSink(sink) and
isSink(sink, state) and
state = Config::DestroyedToBegin(mid)
)
}
}
module Flow = DataFlow::GlobalWithState<Config>;

View File

@@ -62,6 +62,16 @@ module NullAppNameCreateProcessFunctionConfig implements DataFlow::ConfigSig {
val = call.getArgument(call.getApplicationNameArgumentId())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(CreateProcessFunctionCall call | result = call.getLocation() |
sink.asExpr() = call.getArgument(call.getApplicationNameArgumentId())
)
}
}
module NullAppNameCreateProcessFunction = DataFlow::Global<NullAppNameCreateProcessFunctionConfig>;
@@ -82,6 +92,16 @@ module QuotedCommandInCreateProcessFunctionConfig implements DataFlow::ConfigSig
val = call.getArgument(call.getCommandLineArgumentId())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(CreateProcessFunctionCall call | result = call.getLocation() |
sink.asExpr() = call.getArgument(call.getCommandLineArgumentId())
)
}
}
module QuotedCommandInCreateProcessFunction =

View File

@@ -37,6 +37,16 @@ module NullDaclConfig implements DataFlow::ConfigSig {
val = call.getArgument(2)
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(SetSecurityDescriptorDaclFunctionCall call | result = call.getLocation() |
sink.asExpr() = call.getArgument(2)
)
}
}
module NullDaclFlow = DataFlow::Global<NullDaclConfig>;
@@ -68,6 +78,10 @@ module NonNullDaclConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) {
exists(SetSecurityDescriptorDaclFunctionCall call | sink.asExpr() = call.getArgument(2))
}
predicate observeDiffInformedIncrementalMode() {
none() // only used negatively
}
}
module NonNullDaclFlow = DataFlow::Global<NonNullDaclConfig>;

View File

@@ -65,6 +65,16 @@ module Config implements DataFlow::ConfigSig {
iFrom1 != iFrom2
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
exists(Expr raise | result = raise.getLocation() |
sensitiveCondition([sink.asExpr(), sink.asIndirectExpr()], raise)
)
}
}
module Flow = TaintTracking::Global<Config>;

View File

@@ -178,6 +178,10 @@ module Config implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(UnsafeCast cast).getUnconverted() }
int fieldFlowBranchLimit() { result = 0 }
predicate observeDiffInformedIncrementalMode() {
none() // used both positively and negatively
}
}
module Flow = DataFlow::Global<Config>;

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `cpp/short-global-name` query will no longer give alerts for instantiations of template variables, only for the template itself.

View File

@@ -183,6 +183,20 @@ module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig {
pointerArithOverflow(pai, _)
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) {
exists(Variable v | result = v.getLocation() | isSourceImpl(source, v))
}
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(PointerArithmeticInstruction pai, Instruction deref |
result = [pai, deref].getLocation() and
isInvalidPointerDerefSink2(sink, deref, _) and
isSink(sink, ArrayAddressToDerefConfig::TOverflowArithmetic(pai))
)
}
}
module ArrayAddressToDerefFlow = DataFlow::GlobalWithState<ArrayAddressToDerefConfig>;

View File

@@ -28,6 +28,14 @@ module DecompressionTaintConfig implements DataFlow::ConfigSig {
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
any(DecompressionFlowStep s).isAdditionalFlowStep(node1, node2)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(FunctionCall fc | result = [sink.getLocation(), fc.getLocation()] | isSink(fc, sink))
}
}
module DecompressionTaint = TaintTracking::Global<DecompressionTaintConfig>;

View File

@@ -44,6 +44,8 @@
| test.c:198:8:198:8 | b |
| test.c:206:7:206:8 | ! ... |
| test.c:206:8:206:8 | c |
| test.c:215:6:215:18 | call to __builtin_expect |
| test.c:219:9:219:22 | call to __builtin_expect |
| test.cpp:18:8:18:10 | call to get |
| test.cpp:31:7:31:13 | ... == ... |
| test.cpp:42:13:42:20 | call to getABool |
@@ -92,3 +94,15 @@
| test.cpp:241:9:241:43 | ... && ... |
| test.cpp:241:22:241:30 | ... == ... |
| test.cpp:241:35:241:43 | ... == ... |
| test.cpp:247:6:247:18 | ... == ... |
| test.cpp:253:6:253:18 | ... != ... |
| test.cpp:260:6:260:18 | ... == ... |
| test.cpp:266:6:266:18 | ... != ... |
| test.cpp:273:6:273:17 | ... == ... |
| test.cpp:279:6:279:17 | ... != ... |
| test.cpp:287:6:287:19 | ... == ... |
| test.cpp:293:6:293:19 | ... != ... |
| test.cpp:300:6:300:19 | ... == ... |
| test.cpp:306:6:306:19 | ... != ... |
| test.cpp:312:6:312:18 | ... == ... |
| test.cpp:318:6:318:18 | ... != ... |

View File

@@ -38,4 +38,4 @@ where
|
msg = left + op + k + " when " + guard + " is " + value
)
select guard.getLocation().getStartLine(), msg
select guard, msg

View File

@@ -1,165 +1,196 @@
| test.c:7:9:7:13 | ... > ... | false | 10 | 11 |
| test.c:7:9:7:13 | ... > ... | true | 7 | 9 |
| test.c:17:8:17:12 | ... < ... | true | 17 | 17 |
| test.c:17:8:17:12 | ... < ... | true | 18 | 18 |
| test.c:17:8:17:21 | ... && ... | true | 18 | 18 |
| test.c:17:17:17:21 | ... > ... | true | 18 | 18 |
| test.c:26:11:26:15 | ... > ... | false | 2 | 2 |
| test.c:26:11:26:15 | ... > ... | false | 31 | 34 |
| test.c:26:11:26:15 | ... > ... | false | 34 | 34 |
| test.c:26:11:26:15 | ... > ... | false | 39 | 42 |
| test.c:26:11:26:15 | ... > ... | false | 42 | 42 |
| test.c:26:11:26:15 | ... > ... | false | 42 | 44 |
| test.c:26:11:26:15 | ... > ... | false | 45 | 45 |
| test.c:26:11:26:15 | ... > ... | false | 45 | 47 |
| test.c:26:11:26:15 | ... > ... | false | 51 | 53 |
| test.c:26:11:26:15 | ... > ... | false | 56 | 58 |
| test.c:26:11:26:15 | ... > ... | false | 58 | 58 |
| test.c:26:11:26:15 | ... > ... | false | 58 | 66 |
| test.c:26:11:26:15 | ... > ... | false | 62 | 62 |
| test.c:26:11:26:15 | ... > ... | true | 26 | 28 |
| test.c:34:16:34:21 | ... < ... | false | 2 | 2 |
| test.c:34:16:34:21 | ... < ... | false | 39 | 42 |
| test.c:34:16:34:21 | ... < ... | false | 42 | 42 |
| test.c:34:16:34:21 | ... < ... | false | 42 | 44 |
| test.c:34:16:34:21 | ... < ... | false | 45 | 45 |
| test.c:34:16:34:21 | ... < ... | false | 45 | 47 |
| test.c:34:16:34:21 | ... < ... | false | 51 | 53 |
| test.c:34:16:34:21 | ... < ... | false | 56 | 58 |
| test.c:34:16:34:21 | ... < ... | false | 58 | 58 |
| test.c:34:16:34:21 | ... < ... | false | 58 | 66 |
| test.c:34:16:34:21 | ... < ... | false | 62 | 62 |
| test.c:34:16:34:21 | ... < ... | true | 34 | 34 |
| test.c:42:16:42:21 | ... < ... | true | 42 | 42 |
| test.c:42:16:42:21 | ... < ... | true | 42 | 44 |
| test.c:42:16:42:21 | ... < ... | true | 45 | 45 |
| test.c:42:16:42:21 | ... < ... | true | 45 | 47 |
| test.c:42:16:42:21 | ... < ... | true | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | false | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | false | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | true | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | true | 45 | 47 |
| test.c:45:16:45:20 | ... > ... | true | 45 | 47 |
| test.c:58:9:58:14 | ... == ... | false | 58 | 58 |
| test.c:58:9:58:14 | ... == ... | false | 62 | 62 |
| test.c:58:9:58:23 | ... \|\| ... | false | 62 | 62 |
| test.c:58:19:58:23 | ... < ... | false | 62 | 62 |
| test.c:75:9:75:14 | ... == ... | false | 78 | 79 |
| test.c:75:9:75:14 | ... == ... | true | 75 | 77 |
| test.c:85:8:85:13 | ... == ... | true | 85 | 85 |
| test.c:85:8:85:13 | ... == ... | true | 86 | 86 |
| test.c:85:8:85:23 | ... && ... | true | 86 | 86 |
| test.c:85:18:85:23 | ... != ... | true | 86 | 86 |
| test.c:94:11:94:16 | ... != ... | false | 70 | 70 |
| test.c:94:11:94:16 | ... != ... | false | 99 | 102 |
| test.c:94:11:94:16 | ... != ... | false | 102 | 102 |
| test.c:94:11:94:16 | ... != ... | false | 107 | 109 |
| test.c:94:11:94:16 | ... != ... | false | 109 | 109 |
| test.c:94:11:94:16 | ... != ... | false | 109 | 117 |
| test.c:94:11:94:16 | ... != ... | false | 113 | 113 |
| test.c:94:11:94:16 | ... != ... | true | 94 | 96 |
| test.c:102:16:102:21 | ... < ... | false | 70 | 70 |
| test.c:102:16:102:21 | ... < ... | false | 107 | 109 |
| test.c:102:16:102:21 | ... < ... | false | 109 | 109 |
| test.c:102:16:102:21 | ... < ... | false | 109 | 117 |
| test.c:102:16:102:21 | ... < ... | false | 113 | 113 |
| test.c:102:16:102:21 | ... < ... | true | 102 | 102 |
| test.c:109:9:109:14 | ... == ... | false | 109 | 109 |
| test.c:109:9:109:14 | ... == ... | false | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | false | 113 | 113 |
| test.c:109:19:109:23 | ... < ... | false | 113 | 113 |
| test.c:126:7:126:7 | 1 | true | 126 | 126 |
| test.c:126:7:126:7 | 1 | true | 126 | 128 |
| test.c:126:7:126:7 | 1 | true | 131 | 131 |
| test.c:126:7:126:7 | 1 | true | 131 | 132 |
| test.c:126:7:126:7 | 1 | true | 134 | 123 |
| test.c:126:7:126:28 | ... && ... | true | 126 | 128 |
| test.c:126:12:126:26 | call to test3_condition | true | 126 | 128 |
| test.c:131:7:131:7 | b | true | 131 | 132 |
| test.c:137:7:137:7 | 0 | false | 142 | 136 |
| test.c:146:7:146:8 | ! ... | true | 146 | 147 |
| test.c:146:8:146:8 | x | false | 146 | 147 |
| test.c:152:8:152:8 | p | true | 152 | 154 |
| test.c:158:8:158:9 | ! ... | true | 158 | 160 |
| test.c:158:9:158:9 | p | false | 158 | 160 |
| test.c:164:8:164:8 | s | true | 164 | 166 |
| test.c:170:8:170:9 | ! ... | true | 170 | 172 |
| test.c:170:9:170:9 | s | false | 170 | 172 |
| test.c:176:8:176:15 | ! ... | true | 176 | 178 |
| test.c:176:10:176:14 | ... < ... | false | 176 | 178 |
| test.c:182:8:182:34 | ! ... | true | 182 | 184 |
| test.c:182:10:182:20 | ... >= ... | true | 181 | 182 |
| test.c:182:10:182:20 | ... >= ... | true | 182 | 182 |
| test.c:182:10:182:33 | ... && ... | false | 182 | 184 |
| test.c:182:10:182:33 | ... && ... | true | 181 | 182 |
| test.c:182:25:182:33 | ... < ... | true | 181 | 182 |
| test.c:190:7:190:8 | ! ... | true | 190 | 192 |
| test.c:190:8:190:8 | c | false | 190 | 192 |
| test.c:198:7:198:8 | ! ... | true | 198 | 200 |
| test.c:198:8:198:8 | b | false | 198 | 200 |
| test.c:206:7:206:8 | ! ... | true | 206 | 208 |
| test.c:206:8:206:8 | c | false | 206 | 208 |
| test.cpp:18:8:18:10 | call to get | true | 19 | 19 |
| test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 |
| test.cpp:31:7:31:13 | ... == ... | true | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | true | 31 | 32 |
| test.cpp:42:13:42:20 | call to getABool | true | 43 | 45 |
| test.cpp:61:10:61:10 | i | Case[0] | 62 | 64 |
| test.cpp:61:10:61:10 | i | Case[1] | 65 | 66 |
| test.cpp:74:10:74:10 | i | Case[0..10] | 75 | 77 |
| test.cpp:74:10:74:10 | i | Case[11..20] | 78 | 79 |
| test.cpp:93:6:93:6 | c | true | 93 | 94 |
| test.cpp:99:6:99:6 | f | true | 99 | 100 |
| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
| test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 |
| test.cpp:122:9:122:9 | b | true | 123 | 125 |
| test.cpp:122:9:122:9 | b | true | 125 | 125 |
| test.cpp:125:13:125:20 | ! ... | true | 125 | 125 |
| test.cpp:125:14:125:17 | call to safe | false | 125 | 125 |
| test.cpp:131:6:131:21 | call to __builtin_expect | true | 131 | 132 |
| test.cpp:135:6:135:21 | call to __builtin_expect | true | 135 | 136 |
| test.cpp:141:6:141:21 | call to __builtin_expect | true | 141 | 142 |
| test.cpp:145:6:145:21 | call to __builtin_expect | true | 145 | 146 |
| test.cpp:152:7:152:8 | ! ... | true | 152 | 153 |
| test.cpp:152:8:152:8 | b | false | 152 | 153 |
| test.cpp:160:7:160:8 | ! ... | true | 160 | 162 |
| test.cpp:160:8:160:8 | c | false | 160 | 162 |
| test.cpp:168:7:168:8 | ! ... | true | 168 | 170 |
| test.cpp:168:8:168:8 | b | false | 168 | 170 |
| test.cpp:176:7:176:8 | ! ... | true | 176 | 178 |
| test.cpp:176:8:176:8 | c | false | 176 | 178 |
| test.cpp:182:6:182:16 | ! ... | false | 185 | 188 |
| test.cpp:182:6:182:16 | ! ... | true | 182 | 184 |
| test.cpp:182:8:182:9 | b1 | true | 181 | 182 |
| test.cpp:182:8:182:9 | b1 | true | 182 | 182 |
| test.cpp:182:8:182:15 | ... && ... | false | 182 | 184 |
| test.cpp:182:8:182:15 | ... && ... | true | 181 | 182 |
| test.cpp:182:8:182:15 | ... && ... | true | 185 | 188 |
| test.cpp:182:14:182:15 | b2 | true | 181 | 182 |
| test.cpp:193:6:193:16 | ! ... | false | 197 | 199 |
| test.cpp:193:6:193:16 | ! ... | true | 193 | 196 |
| test.cpp:193:8:193:9 | b1 | false | 192 | 193 |
| test.cpp:193:8:193:9 | b1 | false | 193 | 193 |
| test.cpp:193:8:193:15 | ... \|\| ... | false | 192 | 193 |
| test.cpp:193:8:193:15 | ... \|\| ... | false | 193 | 196 |
| test.cpp:193:8:193:15 | ... \|\| ... | true | 197 | 199 |
| test.cpp:193:14:193:15 | b2 | false | 192 | 193 |
| test.cpp:211:9:211:15 | ... == ... | true | 211 | 212 |
| test.cpp:214:9:214:17 | ... == ... | true | 214 | 215 |
| test.cpp:217:9:217:15 | ... == ... | true | 217 | 218 |
| test.cpp:220:9:220:14 | ... == ... | true | 220 | 221 |
| test.cpp:223:9:223:16 | ... == ... | true | 223 | 224 |
| test.cpp:226:9:226:14 | ... == ... | true | 226 | 227 |
| test.cpp:229:9:229:14 | ... == ... | true | 229 | 230 |
| test.cpp:232:9:232:18 | ... == ... | true | 232 | 233 |
| test.cpp:235:9:235:17 | ... == ... | true | 235 | 236 |
| test.cpp:238:9:238:17 | ... == ... | true | 238 | 239 |
| test.cpp:241:9:241:17 | ... == ... | true | 241 | 241 |
| test.cpp:241:9:241:17 | ... == ... | true | 241 | 242 |
| test.cpp:241:9:241:30 | ... && ... | true | 241 | 241 |
| test.cpp:241:9:241:30 | ... && ... | true | 241 | 242 |
| test.cpp:241:9:241:43 | ... && ... | true | 241 | 242 |
| test.cpp:241:22:241:30 | ... == ... | true | 241 | 241 |
| test.cpp:241:22:241:30 | ... == ... | true | 241 | 242 |
| test.cpp:241:35:241:43 | ... == ... | true | 241 | 242 |
| test.c:7:9:7:13 | ... > ... | false | test.c:10:12:11:14 | { ... } |
| test.c:7:9:7:13 | ... > ... | true | test.c:7:16:9:14 | { ... } |
| test.c:17:8:17:12 | ... < ... | true | test.c:17:17:17:21 | y |
| test.c:17:8:17:12 | ... < ... | true | test.c:18:9:18:14 | ExprStmt |
| test.c:17:8:17:21 | ... && ... | true | test.c:18:9:18:14 | ExprStmt |
| test.c:17:17:17:21 | ... > ... | true | test.c:18:9:18:14 | ExprStmt |
| test.c:26:11:26:15 | ... > ... | false | test.c:2:5:2:8 | test |
| test.c:26:11:26:15 | ... > ... | false | test.c:31:5:34:13 | ExprStmt |
| test.c:26:11:26:15 | ... > ... | false | test.c:34:16:34:21 | j |
| test.c:26:11:26:15 | ... > ... | false | test.c:34:29:34:26 | { ... } |
| test.c:26:11:26:15 | ... > ... | false | test.c:39:5:42:13 | ExprStmt |
| test.c:26:11:26:15 | ... > ... | false | test.c:42:5:42:26 | label ...: |
| test.c:26:11:26:15 | ... > ... | false | test.c:42:16:42:21 | j |
| test.c:26:11:26:15 | ... > ... | false | test.c:42:29:44:16 | { ... } |
| test.c:26:11:26:15 | ... > ... | false | test.c:45:13:45:20 | if (...) ... |
| test.c:26:11:26:15 | ... > ... | false | test.c:45:23:47:22 | { ... } |
| test.c:26:11:26:15 | ... > ... | false | test.c:51:14:53:21 | { ... } |
| test.c:26:11:26:15 | ... > ... | false | test.c:56:5:58:14 | label ...: |
| test.c:26:11:26:15 | ... > ... | false | test.c:58:19:58:23 | y |
| test.c:26:11:26:15 | ... > ... | false | test.c:58:26:66:12 | { ... } |
| test.c:26:11:26:15 | ... > ... | false | test.c:62:9:62:16 | return ... |
| test.c:26:11:26:15 | ... > ... | true | test.c:26:18:28:11 | { ... } |
| test.c:34:16:34:21 | ... < ... | false | test.c:2:5:2:8 | test |
| test.c:34:16:34:21 | ... < ... | false | test.c:39:5:42:13 | ExprStmt |
| test.c:34:16:34:21 | ... < ... | false | test.c:42:5:42:26 | label ...: |
| test.c:34:16:34:21 | ... < ... | false | test.c:42:16:42:21 | j |
| test.c:34:16:34:21 | ... < ... | false | test.c:42:29:44:16 | { ... } |
| test.c:34:16:34:21 | ... < ... | false | test.c:45:13:45:20 | if (...) ... |
| test.c:34:16:34:21 | ... < ... | false | test.c:45:23:47:22 | { ... } |
| test.c:34:16:34:21 | ... < ... | false | test.c:51:14:53:21 | { ... } |
| test.c:34:16:34:21 | ... < ... | false | test.c:56:5:58:14 | label ...: |
| test.c:34:16:34:21 | ... < ... | false | test.c:58:19:58:23 | y |
| test.c:34:16:34:21 | ... < ... | false | test.c:58:26:66:12 | { ... } |
| test.c:34:16:34:21 | ... < ... | false | test.c:62:9:62:16 | return ... |
| test.c:34:16:34:21 | ... < ... | true | test.c:34:29:34:26 | { ... } |
| test.c:42:16:42:21 | ... < ... | true | test.c:42:5:42:26 | label ...: |
| test.c:42:16:42:21 | ... < ... | true | test.c:42:29:44:16 | { ... } |
| test.c:42:16:42:21 | ... < ... | true | test.c:45:13:45:20 | if (...) ... |
| test.c:42:16:42:21 | ... < ... | true | test.c:45:23:47:22 | { ... } |
| test.c:42:16:42:21 | ... < ... | true | test.c:51:14:53:21 | { ... } |
| test.c:44:12:44:16 | ... > ... | false | test.c:42:5:42:26 | label ...: |
| test.c:44:12:44:16 | ... > ... | false | test.c:51:14:53:21 | { ... } |
| test.c:44:12:44:16 | ... > ... | true | test.c:45:13:45:20 | if (...) ... |
| test.c:44:12:44:16 | ... > ... | true | test.c:45:23:47:22 | { ... } |
| test.c:45:16:45:20 | ... > ... | true | test.c:45:23:47:22 | { ... } |
| test.c:58:9:58:14 | ... == ... | false | test.c:58:19:58:23 | y |
| test.c:58:9:58:14 | ... == ... | false | test.c:62:9:62:16 | return ... |
| test.c:58:9:58:23 | ... \|\| ... | false | test.c:62:9:62:16 | return ... |
| test.c:58:19:58:23 | ... < ... | false | test.c:62:9:62:16 | return ... |
| test.c:75:9:75:14 | ... == ... | false | test.c:78:12:79:14 | { ... } |
| test.c:75:9:75:14 | ... == ... | true | test.c:75:17:77:14 | { ... } |
| test.c:85:8:85:13 | ... == ... | true | test.c:85:18:85:23 | y |
| test.c:85:8:85:13 | ... == ... | true | test.c:86:9:86:14 | ExprStmt |
| test.c:85:8:85:23 | ... && ... | true | test.c:86:9:86:14 | ExprStmt |
| test.c:85:18:85:23 | ... != ... | true | test.c:86:9:86:14 | ExprStmt |
| test.c:94:11:94:16 | ... != ... | false | test.c:70:5:70:9 | test2 |
| test.c:94:11:94:16 | ... != ... | false | test.c:99:5:102:13 | ExprStmt |
| test.c:94:11:94:16 | ... != ... | false | test.c:102:16:102:21 | j |
| test.c:94:11:94:16 | ... != ... | false | test.c:102:29:102:26 | { ... } |
| test.c:94:11:94:16 | ... != ... | false | test.c:107:5:109:14 | ExprStmt |
| test.c:94:11:94:16 | ... != ... | false | test.c:109:19:109:23 | y |
| test.c:94:11:94:16 | ... != ... | false | test.c:109:26:117:12 | { ... } |
| test.c:94:11:94:16 | ... != ... | false | test.c:113:9:113:16 | return ... |
| test.c:94:11:94:16 | ... != ... | true | test.c:94:19:96:11 | { ... } |
| test.c:102:16:102:21 | ... < ... | false | test.c:70:5:70:9 | test2 |
| test.c:102:16:102:21 | ... < ... | false | test.c:107:5:109:14 | ExprStmt |
| test.c:102:16:102:21 | ... < ... | false | test.c:109:19:109:23 | y |
| test.c:102:16:102:21 | ... < ... | false | test.c:109:26:117:12 | { ... } |
| test.c:102:16:102:21 | ... < ... | false | test.c:113:9:113:16 | return ... |
| test.c:102:16:102:21 | ... < ... | true | test.c:102:29:102:26 | { ... } |
| test.c:109:9:109:14 | ... == ... | false | test.c:109:19:109:23 | y |
| test.c:109:9:109:14 | ... == ... | false | test.c:113:9:113:16 | return ... |
| test.c:109:9:109:23 | ... \|\| ... | false | test.c:113:9:113:16 | return ... |
| test.c:109:19:109:23 | ... < ... | false | test.c:113:9:113:16 | return ... |
| test.c:126:7:126:7 | 1 | true | test.c:126:12:126:26 | call to test3_condition |
| test.c:126:7:126:7 | 1 | true | test.c:126:31:128:16 | { ... } |
| test.c:126:7:126:7 | 1 | true | test.c:131:3:131:7 | if (...) ... |
| test.c:126:7:126:7 | 1 | true | test.c:131:10:132:16 | { ... } |
| test.c:126:7:126:7 | 1 | true | test.c:134:1:123:10 | return ... |
| test.c:126:7:126:28 | ... && ... | true | test.c:126:31:128:16 | { ... } |
| test.c:126:12:126:26 | call to test3_condition | true | test.c:126:31:128:16 | { ... } |
| test.c:131:7:131:7 | b | true | test.c:131:10:132:16 | { ... } |
| test.c:137:7:137:7 | 0 | false | test.c:142:3:136:10 | return ... |
| test.c:146:7:146:8 | ! ... | true | test.c:146:11:147:9 | { ... } |
| test.c:146:8:146:8 | x | false | test.c:146:11:147:9 | { ... } |
| test.c:152:8:152:8 | p | true | test.c:152:11:154:5 | { ... } |
| test.c:158:8:158:9 | ! ... | true | test.c:158:12:160:5 | { ... } |
| test.c:158:9:158:9 | p | false | test.c:158:12:160:5 | { ... } |
| test.c:164:8:164:8 | s | true | test.c:164:11:166:5 | { ... } |
| test.c:170:8:170:9 | ! ... | true | test.c:170:12:172:5 | { ... } |
| test.c:170:9:170:9 | s | false | test.c:170:12:172:5 | { ... } |
| test.c:176:8:176:15 | ! ... | true | test.c:176:18:178:5 | { ... } |
| test.c:176:10:176:14 | ... < ... | false | test.c:176:18:178:5 | { ... } |
| test.c:182:8:182:34 | ! ... | true | test.c:182:37:184:5 | { ... } |
| test.c:182:10:182:20 | ... >= ... | true | test.c:181:25:182:20 | { ... } |
| test.c:182:10:182:20 | ... >= ... | true | test.c:182:25:182:33 | foo |
| test.c:182:10:182:33 | ... && ... | false | test.c:182:37:184:5 | { ... } |
| test.c:182:10:182:33 | ... && ... | true | test.c:181:25:182:20 | { ... } |
| test.c:182:25:182:33 | ... < ... | true | test.c:181:25:182:20 | { ... } |
| test.c:190:7:190:8 | ! ... | true | test.c:190:11:192:3 | { ... } |
| test.c:190:8:190:8 | c | false | test.c:190:11:192:3 | { ... } |
| test.c:198:7:198:8 | ! ... | true | test.c:198:11:200:3 | { ... } |
| test.c:198:8:198:8 | b | false | test.c:198:11:200:3 | { ... } |
| test.c:206:7:206:8 | ! ... | true | test.c:206:11:208:3 | { ... } |
| test.c:206:8:206:8 | c | false | test.c:206:11:208:3 | { ... } |
| test.c:215:6:215:18 | call to __builtin_expect | true | test.c:215:21:217:5 | { ... } |
| test.c:219:9:219:22 | call to __builtin_expect | true | test.c:219:25:221:5 | { ... } |
| test.cpp:18:8:18:10 | call to get | true | test.cpp:19:5:19:14 | ExprStmt |
| test.cpp:31:7:31:13 | ... == ... | false | test.cpp:30:6:30:16 | doSomething |
| test.cpp:31:7:31:13 | ... == ... | false | test.cpp:34:1:34:1 | return ... |
| test.cpp:31:7:31:13 | ... == ... | true | test.cpp:30:6:30:16 | doSomething |
| test.cpp:31:7:31:13 | ... == ... | true | test.cpp:31:16:32:21 | { ... } |
| test.cpp:42:13:42:20 | call to getABool | true | test.cpp:43:9:45:23 | { ... } |
| test.cpp:61:10:61:10 | i | Case[0] | test.cpp:62:5:64:12 | case ...: |
| test.cpp:61:10:61:10 | i | Case[1] | test.cpp:65:5:66:10 | case ...: |
| test.cpp:74:10:74:10 | i | Case[0..10] | test.cpp:75:5:77:12 | case ...: |
| test.cpp:74:10:74:10 | i | Case[11..20] | test.cpp:78:5:79:10 | case ...: |
| test.cpp:93:6:93:6 | c | true | test.cpp:93:9:94:7 | { ... } |
| test.cpp:99:6:99:6 | f | true | test.cpp:99:9:100:7 | { ... } |
| test.cpp:105:6:105:14 | ... != ... | true | test.cpp:105:17:106:7 | { ... } |
| test.cpp:111:6:111:14 | ... != ... | true | test.cpp:111:17:112:7 | { ... } |
| test.cpp:122:9:122:9 | b | true | test.cpp:123:5:125:20 | { ... } |
| test.cpp:122:9:122:9 | b | true | test.cpp:125:23:125:29 | return ... |
| test.cpp:125:13:125:20 | ! ... | true | test.cpp:125:23:125:29 | return ... |
| test.cpp:125:14:125:17 | call to safe | false | test.cpp:125:23:125:29 | return ... |
| test.cpp:131:6:131:21 | call to __builtin_expect | true | test.cpp:131:40:132:9 | { ... } |
| test.cpp:135:6:135:21 | call to __builtin_expect | true | test.cpp:135:40:136:9 | { ... } |
| test.cpp:141:6:141:21 | call to __builtin_expect | true | test.cpp:141:36:142:9 | { ... } |
| test.cpp:145:6:145:21 | call to __builtin_expect | true | test.cpp:145:36:146:9 | { ... } |
| test.cpp:152:7:152:8 | ! ... | true | test.cpp:152:11:153:9 | { ... } |
| test.cpp:152:8:152:8 | b | false | test.cpp:152:11:153:9 | { ... } |
| test.cpp:160:7:160:8 | ! ... | true | test.cpp:160:11:162:3 | { ... } |
| test.cpp:160:8:160:8 | c | false | test.cpp:160:11:162:3 | { ... } |
| test.cpp:168:7:168:8 | ! ... | true | test.cpp:168:11:170:3 | { ... } |
| test.cpp:168:8:168:8 | b | false | test.cpp:168:11:170:3 | { ... } |
| test.cpp:176:7:176:8 | ! ... | true | test.cpp:176:11:178:3 | { ... } |
| test.cpp:176:8:176:8 | c | false | test.cpp:176:11:178:3 | { ... } |
| test.cpp:182:6:182:16 | ! ... | false | test.cpp:185:10:188:7 | { ... } |
| test.cpp:182:6:182:16 | ! ... | true | test.cpp:182:19:184:7 | { ... } |
| test.cpp:182:8:182:9 | b1 | true | test.cpp:181:41:182:9 | { ... } |
| test.cpp:182:8:182:9 | b1 | true | test.cpp:182:14:182:15 | b2 |
| test.cpp:182:8:182:15 | ... && ... | false | test.cpp:182:19:184:7 | { ... } |
| test.cpp:182:8:182:15 | ... && ... | true | test.cpp:181:41:182:9 | { ... } |
| test.cpp:182:8:182:15 | ... && ... | true | test.cpp:185:10:188:7 | { ... } |
| test.cpp:182:14:182:15 | b2 | true | test.cpp:181:41:182:9 | { ... } |
| test.cpp:193:6:193:16 | ! ... | false | test.cpp:197:10:199:7 | { ... } |
| test.cpp:193:6:193:16 | ! ... | true | test.cpp:193:19:196:7 | { ... } |
| test.cpp:193:8:193:9 | b1 | false | test.cpp:192:40:193:9 | { ... } |
| test.cpp:193:8:193:9 | b1 | false | test.cpp:193:14:193:15 | b2 |
| test.cpp:193:8:193:15 | ... \|\| ... | false | test.cpp:192:40:193:9 | { ... } |
| test.cpp:193:8:193:15 | ... \|\| ... | false | test.cpp:193:19:196:7 | { ... } |
| test.cpp:193:8:193:15 | ... \|\| ... | true | test.cpp:197:10:199:7 | { ... } |
| test.cpp:193:14:193:15 | b2 | false | test.cpp:192:40:193:9 | { ... } |
| test.cpp:211:9:211:15 | ... == ... | true | test.cpp:211:18:212:13 | { ... } |
| test.cpp:214:9:214:17 | ... == ... | true | test.cpp:214:20:215:13 | { ... } |
| test.cpp:217:9:217:15 | ... == ... | true | test.cpp:217:18:218:13 | { ... } |
| test.cpp:220:9:220:14 | ... == ... | true | test.cpp:220:17:221:13 | { ... } |
| test.cpp:223:9:223:16 | ... == ... | true | test.cpp:223:19:224:13 | { ... } |
| test.cpp:226:9:226:14 | ... == ... | true | test.cpp:226:17:227:13 | { ... } |
| test.cpp:229:9:229:14 | ... == ... | true | test.cpp:229:17:230:13 | { ... } |
| test.cpp:232:9:232:18 | ... == ... | true | test.cpp:232:21:233:13 | { ... } |
| test.cpp:235:9:235:17 | ... == ... | true | test.cpp:235:20:236:13 | { ... } |
| test.cpp:238:9:238:17 | ... == ... | true | test.cpp:238:20:239:13 | { ... } |
| test.cpp:241:9:241:17 | ... == ... | true | test.cpp:241:22:241:30 | ms |
| test.cpp:241:9:241:17 | ... == ... | true | test.cpp:241:35:241:43 | ms |
| test.cpp:241:9:241:17 | ... == ... | true | test.cpp:241:46:242:13 | { ... } |
| test.cpp:241:9:241:30 | ... && ... | true | test.cpp:241:35:241:43 | ms |
| test.cpp:241:9:241:30 | ... && ... | true | test.cpp:241:46:242:13 | { ... } |
| test.cpp:241:9:241:43 | ... && ... | true | test.cpp:241:46:242:13 | { ... } |
| test.cpp:241:22:241:30 | ... == ... | true | test.cpp:241:35:241:43 | ms |
| test.cpp:241:22:241:30 | ... == ... | true | test.cpp:241:46:242:13 | { ... } |
| test.cpp:241:35:241:43 | ... == ... | true | test.cpp:241:46:242:13 | { ... } |
| test.cpp:247:6:247:18 | ... == ... | false | test.cpp:249:10:251:3 | { ... } |
| test.cpp:247:6:247:18 | ... == ... | true | test.cpp:247:21:249:3 | { ... } |
| test.cpp:253:6:253:18 | ... != ... | false | test.cpp:255:10:257:3 | { ... } |
| test.cpp:253:6:253:18 | ... != ... | true | test.cpp:253:21:255:3 | { ... } |
| test.cpp:260:6:260:18 | ... == ... | false | test.cpp:262:10:264:3 | { ... } |
| test.cpp:260:6:260:18 | ... == ... | true | test.cpp:260:21:262:3 | { ... } |
| test.cpp:266:6:266:18 | ... != ... | false | test.cpp:268:10:270:3 | { ... } |
| test.cpp:266:6:266:18 | ... != ... | true | test.cpp:266:21:268:3 | { ... } |
| test.cpp:273:6:273:17 | ... == ... | false | test.cpp:275:10:277:3 | { ... } |
| test.cpp:273:6:273:17 | ... == ... | true | test.cpp:273:20:275:3 | { ... } |
| test.cpp:279:6:279:17 | ... != ... | false | test.cpp:281:10:283:3 | { ... } |
| test.cpp:279:6:279:17 | ... != ... | true | test.cpp:279:20:281:3 | { ... } |
| test.cpp:287:6:287:19 | ... == ... | false | test.cpp:289:10:291:3 | { ... } |
| test.cpp:287:6:287:19 | ... == ... | true | test.cpp:287:22:289:3 | { ... } |
| test.cpp:293:6:293:19 | ... != ... | false | test.cpp:295:10:297:3 | { ... } |
| test.cpp:293:6:293:19 | ... != ... | true | test.cpp:293:22:295:3 | { ... } |
| test.cpp:300:6:300:19 | ... == ... | false | test.cpp:302:10:304:3 | { ... } |
| test.cpp:300:6:300:19 | ... == ... | true | test.cpp:300:22:302:3 | { ... } |
| test.cpp:306:6:306:19 | ... != ... | false | test.cpp:308:10:310:3 | { ... } |
| test.cpp:306:6:306:19 | ... != ... | true | test.cpp:306:22:308:3 | { ... } |
| test.cpp:312:6:312:18 | ... == ... | false | test.cpp:314:10:316:3 | { ... } |
| test.cpp:312:6:312:18 | ... == ... | true | test.cpp:312:21:314:3 | { ... } |
| test.cpp:318:6:318:18 | ... != ... | false | test.cpp:320:10:322:3 | { ... } |
| test.cpp:318:6:318:18 | ... != ... | true | test.cpp:318:21:320:3 | { ... } |

View File

@@ -7,10 +7,6 @@
import cpp
import semmle.code.cpp.controlflow.Guards
from GuardCondition guard, AbstractValue value, int start, int end
where
exists(BasicBlock block |
guard.valueControls(block, value) and
block.hasLocationInfo(_, start, _, end, _)
)
select guard, value, start, end
from GuardCondition guard, AbstractValue value, BasicBlock block
where guard.valueControls(block, value)
select guard, value, block

View File

@@ -8,31 +8,23 @@ import cpp
import semmle.code.cpp.controlflow.Guards
query predicate binary(
GuardCondition guard, Expr left, string op, Expr right, int k, int start, int end
GuardCondition guard, Expr left, string op, Expr right, int k, BasicBlock block
) {
exists(BasicBlock block |
guard.ensuresLt(left, right, k, block, true) and op = "<"
or
guard.ensuresLt(left, right, k, block, false) and op = ">="
or
guard.ensuresEq(left, right, k, block, true) and op = "=="
or
guard.ensuresEq(left, right, k, block, false) and op = "!="
|
block.hasLocationInfo(_, start, _, end, _)
)
guard.ensuresLt(left, right, k, block, true) and op = "<"
or
guard.ensuresLt(left, right, k, block, false) and op = ">="
or
guard.ensuresEq(left, right, k, block, true) and op = "=="
or
guard.ensuresEq(left, right, k, block, false) and op = "!="
}
query predicate unary(GuardCondition guard, Expr left, string op, int k, int start, int end) {
exists(BasicBlock block |
guard.ensuresLt(left, k, block, true) and op = "<"
or
guard.ensuresLt(left, k, block, false) and op = ">="
or
guard.ensuresEq(left, k, block, true) and op = "=="
or
guard.ensuresEq(left, k, block, false) and op = "!="
|
block.hasLocationInfo(_, start, _, end, _)
)
query predicate unary(GuardCondition guard, Expr left, string op, int k, BasicBlock block) {
guard.ensuresLt(left, k, block, true) and op = "<"
or
guard.ensuresLt(left, k, block, false) and op = ">="
or
guard.ensuresEq(left, k, block, true) and op = "=="
or
guard.ensuresEq(left, k, block, false) and op = "!="
}

View File

@@ -206,4 +206,17 @@ void test14(int a, int b) {
if (!c) {
}
}
}
# define likely(x) __builtin_expect(!!(x), 1)
void test15(int a, int b)
{
if (likely(a > b)) {
}
if (likely(a > 42)) {
}
}

View File

@@ -242,3 +242,82 @@ int test_types(signed char sc, unsigned long ul, float f, double d, bool b, Myst
ctr++;
}
}
void test_cmp_implies(int a, int b) {
if((a == b) == 0) {
} else {
}
if((a == b) != 0) {
} else {
}
if((a != b) == 0) {
} else {
}
if((a != b) != 0) {
} else {
}
if((a < b) == 0) {
} else {
}
if((a < b) != 0) {
} else {
}
}
void test_cmp_implies_unary(int a) {
if((a == 42) == 0) {
} else {
}
if((a == 42) != 0) {
} else {
}
if((a != 42) == 0) {
} else {
}
if((a != 42) != 0) {
} else {
}
if((a < 42) == 0) {
} else {
}
if((a < 42) != 0) {
} else {
}
}

View File

@@ -1,2 +1,7 @@
| main.cpp:3:5:3:5 | x | Poor global variable name 'x'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:4:5:4:6 | ys | Poor global variable name 'ys'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:9:5:9:6 | v1 | Poor global variable name 'v1'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:10:5:10:6 | v2 | Poor global variable name 'v2'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:12:5:12:5 | v3 | Poor global variable name 'v3'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:14:5:14:5 | v4 | Poor global variable name 'v4'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
| main.cpp:16:5:16:5 | v5 | Poor global variable name 'v5'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |

View File

@@ -5,3 +5,19 @@ int ys[1000000]; // BAD: too short
int descriptive_name; // GOOD: sufficient
static int z; // GOOD: not a global
int v1; // BAD: too short
int v2; // BAD: too short
template <typename T>
T v3; // BAD: too short
template <typename T>
T v4; // BAD: too short
template <typename T>
T v5; // BAD: too short
void use_some_fs() {
v2 = 100;
v4<int> = 200;
v5<int> = 300;
v5<const char *> = "string";
}

View File

@@ -1,4 +1,5 @@
edges
| test.c:10:31:10:32 | sscanf output argument | test.c:11:7:11:7 | x | provenance | |
| test.cpp:34:15:34:16 | scanf output argument | test.cpp:35:7:35:7 | i | provenance | |
| test.cpp:41:19:41:20 | scanf output argument | test.cpp:43:8:43:8 | i | provenance | |
| test.cpp:58:19:58:20 | scanf output argument | test.cpp:60:8:60:8 | i | provenance | |
@@ -56,6 +57,8 @@ edges
| test.cpp:567:35:567:36 | scanf output argument | test.cpp:569:9:569:9 | i | provenance | |
| test.cpp:575:30:575:31 | scanf output argument | test.cpp:577:9:577:9 | i | provenance | |
nodes
| test.c:10:31:10:32 | sscanf output argument | semmle.label | sscanf output argument |
| test.c:11:7:11:7 | x | semmle.label | x |
| test.cpp:34:15:34:16 | scanf output argument | semmle.label | scanf output argument |
| test.cpp:35:7:35:7 | i | semmle.label | i |
| test.cpp:41:19:41:20 | scanf output argument | semmle.label | scanf output argument |
@@ -186,5 +189,3 @@ subpaths
| test.cpp:484:9:484:9 | i | test.cpp:480:25:480:26 | scanf output argument | test.cpp:484:9:484:9 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:480:13:480:17 | call to scanf | call to scanf |
| test.cpp:495:8:495:8 | i | test.cpp:491:25:491:26 | scanf output argument | test.cpp:495:8:495:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:491:13:491:17 | call to scanf | call to scanf |
| test.cpp:545:8:545:8 | f | test.cpp:541:43:541:44 | sscanf output argument | test.cpp:545:8:545:8 | f | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 3. | test.cpp:541:10:541:15 | call to sscanf | call to sscanf |
| test.cpp:569:9:569:9 | i | test.cpp:567:35:567:36 | scanf output argument | test.cpp:569:9:569:9 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:567:23:567:27 | call to scanf | call to scanf |
| test.cpp:577:9:577:9 | i | test.cpp:575:30:575:31 | scanf output argument | test.cpp:577:9:577:9 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:575:18:575:22 | call to scanf | call to scanf |

View File

@@ -0,0 +1,13 @@
# define likely(x) __builtin_expect(!!(x), 1)
int sscanf(const char *s, const char *format, ...);
void use(int i);
void test_likely(const char* s, const char* format)
{
int x;
if (likely(sscanf(s, format, &x) == 1)) {
use(x); // GOOD
}
}

View File

@@ -566,7 +566,7 @@ void test_scanf_compared_in_conjunct_right(bool b) {
int i;
bool success = b && scanf("%d", &i) == 1;
if(success) {
use(i); // GOOD [FALSE POSITIVE]
use(i); // GOOD
}
}
@@ -574,6 +574,6 @@ void test_scanf_compared_in_conjunct_left(bool b) {
int i;
bool success = scanf("%d", &i) == 1 && b;
if(success) {
use(i); // GOOD [FALSE POSITIVE]
use(i); // GOOD
}
}

View File

@@ -6,3 +6,4 @@
| test.cpp:83:7:83:40 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:78:16:78:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:87:7:87:38 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:7:57:7:77 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:107:13:107:42 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:105:16:105:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:109:7:109:8 | ok | This expression conflates OK and non-OK results from $@. | test.cpp:105:16:105:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |

View File

@@ -0,0 +1,121 @@
typedef unsigned long size_t;
typedef struct sqlite3 sqlite3;
typedef struct sqlite3_stmt sqlite3_stmt;
typedef struct sqlite3_str sqlite3_str;
int snprintf(char *str, size_t size, const char *format, ...);
int sqlite3_open(const char *filename, sqlite3 **ppDb);
int sqlite3_close(sqlite3*);
int sqlite3_exec(sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg);
int sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
int sqlite3_step(sqlite3_stmt*);
int sqlite3_finalize(sqlite3_stmt*);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
sqlite3_str* sqlite3_str_new(sqlite3*);
void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...);
char* sqlite3_str_finish(sqlite3_str*);
#define SQLITE_TRANSIENT ((void(*)(void*))-1)
// Simulate a sensitive value
const char* getSensitivePassword() {
return "super_secret_password";
}
void storePasswordCleartext(sqlite3* db, const char* password) {
// BAD: Storing sensitive data in cleartext
char sql[256];
// Unsafe: no escaping, for test purposes only
snprintf(sql, sizeof(sql), "INSERT INTO users(password) VALUES('%s');", password); // $ Source
char* errMsg = 0;
sqlite3_exec(db, sql, 0, 0, &errMsg); // $ Alert
}
void storePasswordWithPrepare(sqlite3* db, const char* password) {
// BAD: Storing sensitive data in cleartext using sqlite3_prepare
char sql[256];
snprintf(sql, sizeof(sql), "INSERT INTO users(password) VALUES('%s');", password); // $ Source
sqlite3_stmt* stmt = 0;
sqlite3_prepare_v2(db, sql, -1, &stmt, 0); // $ Alert
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
void storePasswordWithBind(sqlite3* db, const char* password) {
// BAD: Storing sensitive data in cleartext using sqlite3_bind_text
const char* sql = "INSERT INTO users(password) VALUES(?);";
sqlite3_stmt* stmt = 0;
sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT); // $ Alert
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
void storePasswordWithAppendf(sqlite3_str* pStr, const char* password) {
// BAD: Storing sensitive data in cleartext using sqlite3_str_appendf
sqlite3_str_appendf(pStr, "INSERT INTO users(password) VALUES('%s');", password); // $ Alert
}
// Example sanitizer: hashes the sensitive value before storage
void hashSensitiveValue(const char* input, char* output, size_t outSize) {
// Dummy hash for illustration (not cryptographically secure)
unsigned int hash = 5381;
for (const char* p = input; *p; ++p)
hash = ((hash << 5) + hash) + (unsigned char)(*p);
snprintf(output, outSize, "%u", hash);
}
void storeSanitizedPasswordCleartext(sqlite3* db, const char* password) {
// GOOD: Sanitizing sensitive data before storage
char hashed[64];
hashSensitiveValue(password, hashed, sizeof(hashed));
char sql[256];
snprintf(sql, sizeof(sql), "INSERT INTO users(password) VALUES('%s');", hashed);
char* errMsg = 0;
sqlite3_exec(db, sql, 0, 0, &errMsg);
}
void storeSanitizedPasswordWithBind(sqlite3* db, const char* password) {
// GOOD: Sanitizing sensitive data before storage with bind
char hashed[64];
hashSensitiveValue(password, hashed, sizeof(hashed));
const char* sql = "INSERT INTO users(password) VALUES(?);";
sqlite3_stmt* stmt = 0;
sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
sqlite3_bind_text(stmt, 1, hashed, -1, SQLITE_TRANSIENT);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
void storeSanitizedPasswordWithAppendf(sqlite3_str* pStr, const char* password) {
// GOOD: Sanitizing sensitive data before storage with appendf
char hashed[64];
hashSensitiveValue(password, hashed, sizeof(hashed));
sqlite3_str_appendf(pStr, "INSERT INTO users(password) VALUES('%s');", hashed);
}
int main() {
sqlite3* db = 0;
sqlite3_open(":memory:", &db);
// Create table
const char* createTableSQL = "CREATE TABLE users(id INTEGER PRIMARY KEY, password TEXT);";
sqlite3_exec(db, createTableSQL, 0, 0, 0);
const char* sensitive = getSensitivePassword();
storePasswordCleartext(db, sensitive);
storePasswordWithPrepare(db, sensitive);
storePasswordWithBind(db, sensitive);
storeSanitizedPasswordCleartext(db, sensitive);
storeSanitizedPasswordWithBind(db, sensitive);
// If sqlite3_str is available
sqlite3_str* pStr = sqlite3_str_new(db);
storePasswordWithAppendf(pStr, sensitive);
storeSanitizedPasswordWithAppendf(pStr, sensitive);
sqlite3_str_finish(pStr);
sqlite3_close(db);
return 0;
}

View File

@@ -0,0 +1,16 @@
#select
| CleartextSqliteDatabase.cpp:31:5:31:16 | call to sqlite3_exec | CleartextSqliteDatabase.cpp:29:77:29:84 | password | CleartextSqliteDatabase.cpp:31:22:31:24 | *sql | This SQLite call may store $@ in a non-encrypted SQLite database. | CleartextSqliteDatabase.cpp:29:77:29:84 | password | sensitive information |
| CleartextSqliteDatabase.cpp:39:5:39:22 | call to sqlite3_prepare_v2 | CleartextSqliteDatabase.cpp:37:77:37:84 | password | CleartextSqliteDatabase.cpp:39:28:39:30 | *sql | This SQLite call may store $@ in a non-encrypted SQLite database. | CleartextSqliteDatabase.cpp:37:77:37:84 | password | sensitive information |
| CleartextSqliteDatabase.cpp:49:5:49:21 | call to sqlite3_bind_text | CleartextSqliteDatabase.cpp:49:32:49:39 | password | CleartextSqliteDatabase.cpp:49:32:49:39 | password | This SQLite call may store $@ in a non-encrypted SQLite database. | CleartextSqliteDatabase.cpp:49:32:49:39 | password | sensitive information |
| CleartextSqliteDatabase.cpp:56:5:56:23 | call to sqlite3_str_appendf | CleartextSqliteDatabase.cpp:56:76:56:83 | password | CleartextSqliteDatabase.cpp:56:76:56:83 | password | This SQLite call may store $@ in a non-encrypted SQLite database. | CleartextSqliteDatabase.cpp:56:76:56:83 | password | sensitive information |
edges
| CleartextSqliteDatabase.cpp:29:77:29:84 | password | CleartextSqliteDatabase.cpp:31:22:31:24 | *sql | provenance | TaintFunction |
| CleartextSqliteDatabase.cpp:37:77:37:84 | password | CleartextSqliteDatabase.cpp:39:28:39:30 | *sql | provenance | TaintFunction |
nodes
| CleartextSqliteDatabase.cpp:29:77:29:84 | password | semmle.label | password |
| CleartextSqliteDatabase.cpp:31:22:31:24 | *sql | semmle.label | *sql |
| CleartextSqliteDatabase.cpp:37:77:37:84 | password | semmle.label | password |
| CleartextSqliteDatabase.cpp:39:28:39:30 | *sql | semmle.label | *sql |
| CleartextSqliteDatabase.cpp:49:32:49:39 | password | semmle.label | password |
| CleartextSqliteDatabase.cpp:56:76:56:83 | password | semmle.label | password |
subpaths

View File

@@ -0,0 +1,4 @@
query: Security/CWE/CWE-313/CleartextSqliteDatabase.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -17,7 +17,7 @@ runs:
run: |
CODEQL_PATH=$(gh codeql version --format=json | jq -r .unpackedLocation)
# The legacy ASP extractor is not in this repo, so take the one from the nightly build
mv "$CODEQL_PATH/csharp/tools/extractor-asp.jar" "${{ github.workspace }}/csharp/extractor-pack/tools"
mv "$CODEQL_PATH/csharp/tools/extractor-asp.jar" "$GITHUB_WORKSPACE/csharp/extractor-pack/tools"
# Safe guard against using the bundled extractor
rm -rf "$CODEQL_PATH/csharp"
env:

View File

@@ -39,6 +39,15 @@ private module ConditionalBypassConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
// from ConditionalBypass.ql
result = sink.(Sink).getSensitiveMethodCall().getLocation()
}
}
/**

View File

@@ -59,6 +59,10 @@ private module TaintToObjectMethodTrackingConfig implements DataFlow::ConfigSig
predicate isSink(DataFlow::Node sink) { sink instanceof InstanceMethodSink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate observeDiffInformedIncrementalMode() {
any() // used in one of the disjuncts in UnsafeDeserializationUntrustedInput.ql
}
}
/**
@@ -77,6 +81,10 @@ private module JsonConvertTrackingConfig implements DataFlow::ConfigSig {
}
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate observeDiffInformedIncrementalMode() {
any() // used in one of the disjuncts in UnsafeDeserializationUntrustedInput.ql
}
}
/**
@@ -133,6 +141,10 @@ private module TypeNameTrackingConfig implements DataFlow::ConfigSig {
)
)
}
predicate observeDiffInformedIncrementalMode() {
none() // Only used as secondary config in UnsafeDeserializationUntrustedInput.ql
}
}
/**
@@ -149,6 +161,10 @@ private module TaintToConstructorOrStaticMethodTrackingConfig implements DataFlo
predicate isSink(DataFlow::Node sink) { sink instanceof ConstructorOrStaticMethodSink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate observeDiffInformedIncrementalMode() {
any() // used in one of the disjuncts in UnsafeDeserializationUntrustedInput.ql
}
}
/**
@@ -186,6 +202,10 @@ private module TaintToObjectTypeTrackingConfig implements DataFlow::ConfigSig {
oc.getObjectType() instanceof StrongTypeDeserializer
)
}
predicate observeDiffInformedIncrementalMode() {
none() // only used as secondary config in UnsafeDeserializationUntrustedInput.ql
}
}
/**
@@ -210,6 +230,10 @@ private module WeakTypeCreationToUsageTrackingConfig implements DataFlow::Config
sink.asExpr() = mc.getQualifier()
)
}
predicate observeDiffInformedIncrementalMode() {
none() // only used as secondary config in UnsafeDeserializationUntrustedInput.ql
}
}
/**

View File

@@ -24,6 +24,8 @@ module NotThreadSafeCryptoUsageIntoParallelInvokeConfig implements DataFlow::Con
}
predicate isSink(DataFlow::Node sink) { sink instanceof ParallelSink }
predicate observeDiffInformedIncrementalMode() { any() }
}
module NotThreadSafeCryptoUsageIntoParallelInvoke =

View File

@@ -38,6 +38,12 @@ module ConnectionStringConfig implements DataFlow::ConfigSig {
}
predicate isBarrier(DataFlow::Node node) { node instanceof StringFormatSanitizer }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
any(Call call | call.getAnArgument() = sink.asExpr()).getLocation() = result
}
}
/**

View File

@@ -1,7 +1,7 @@
/*
* This Sphinx stylesheet adds some customizations to the default Alabaster theme.
*
* The source for the default stylesheet can be found at
*
* The source for the default stylesheet can be found at
* https://github.com/bitprophet/alabaster/blob/master/alabaster/static/alabaster.css_t
*
* For the classes provided by the primer, see https://unpkg.com/@primer/css/dist/primer.css
@@ -45,7 +45,7 @@ article ul, article ol {
}
.SideNav li {
margin: 10px 0 10px 0px;
margin: 10px 0 10px 0px;
}
.SideNav ul, .SideNav ol, .SideNav li {
@@ -80,20 +80,20 @@ a.reference {
}
a.reference:hover {
text-decoration: none;
text-decoration: none;
}
/* -- ADMONITIONS ---------------------------------------------------------------------------- */
/*
* Override default styling for "admonitions".
/*
* Override default styling for "admonitions".
* This includes: note, tip, important, and caution.
*
*/
div.admonition p.admonition-title {
div.admonition p.admonition-title {
/* Make title same size and font as body, but bold. */
font-family: Lato, sans-serif;
font-family: Lato, sans-serif;
font-size: 14px;
font-weight: bold;
}
@@ -102,7 +102,7 @@ p.admonition-title:after {
content: ""; /* Don't insert a colon after the title */
}
/*
/*
* Don't use yellow for footnote background.
*
*/
@@ -111,7 +111,7 @@ p.admonition-title:after {
background-color: unset;
}
/*
/*
* Add a border with rounded corners around code blocks
* (as in the QL language spec).
*
@@ -198,7 +198,7 @@ blockquote.pull-quote {
background-color: #EEE;
border: #CCC;
border-radius: 5px;
}
}
blockquote.pull-quote:first-line {
font-weight: bold;
@@ -230,6 +230,11 @@ blockquote.pull-quote > :last-child {
font-family: "monospace";
}
/* Fixes a bug in "Supported languages and frameworks" where footnotes were incorrectly indented */
aside .label {
border: 0;
}
/* -- PRINT VIEW ----------------------------------------------------------------------------*/
@media print {
@@ -252,14 +257,14 @@ blockquote.pull-quote > :last-child {
/* -- SMALL SCREEN ------------------------------------------------------------------------------- */
@media screen and (max-width: 875px) {
@media screen and (max-width: 875px) {
/* Overrides strange behaviour caused by default styles */
body {
padding: 0;
}
}
div.footer {
display: block;
}

View File

@@ -79,4 +79,4 @@ JavaScript/TypeScript
* Added taint-steps for :code:`Array.prototype.toReversed`.
* Added taint-steps for :code:`Array.prototype.toSorted`.
* Added support for :code:`String.prototype.matchAll`.
* Added taint-steps for :code:`Array.prototype.reverse`.
* Added taint-steps for :code:`Array.prototype.reverse`\

View File

@@ -117,8 +117,8 @@ Java/Kotlin
* Deleted the deprecated :code:`isLValue` and :code:`isRValue` predicates from the :code:`VarAccess` class, use :code:`isVarWrite` and :code:`isVarRead` respectively instead.
* Deleted the deprecated :code:`getRhs` predicate from the :code:`VarWrite` class, use :code:`getASource` instead.
* Deleted the deprecated :code:`LValue` and :code:`RValue` classes, use :code:`VarWrite` and :code:`VarRead` respectively instead.
* Deleted a lot of deprecated classes ending in ``*Access``, use the corresponding ``*Call`` classes instead.
* Deleted a lot of deprecated predicates ending in ``*Access``, use the corresponding ``*Call`` predicates instead.
* Deleted a lot of deprecated classes ending in :code:`*Access`, use the corresponding :code:`*Call` classes instead.
* Deleted a lot of deprecated predicates ending in :code:`*Access`, use the corresponding :code:`*Call` predicates instead.
* Deleted the deprecated :code:`EnvInput` and :code:`DatabaseInput` classes from :code:`FlowSources.qll`, use the threat models feature instead.
* Deleted some deprecated API predicates from :code:`SensitiveApi.qll`, use the Sink classes from that file instead.
@@ -144,7 +144,7 @@ Ruby
* Deleted the deprecated :code:`ModelClass` and :code:`ModelInstance` classes from :code:`ActiveResource.qll`, use :code:`ModelClassNode` and :code:`ModelClassNode.getAnInstanceReference()` instead.
* Deleted the deprecated :code:`Collection` class from :code:`ActiveResource.qll`, use :code:`CollectionSource` instead.
* Deleted the deprecated :code:`ServiceInstantiation` and :code:`ClientInstantiation` classes from :code:`Twirp.qll`.
* Deleted a lot of deprecated dataflow modules from ``*Query.qll`` files.
* Deleted a lot of deprecated dataflow modules from :code:`*Query.qll` files.
* Deleted the old deprecated TypeTracking library.
Swift

View File

@@ -207,5 +207,5 @@ JavaScript/TypeScript
* Intersection :code:`&&`
* Subtraction :code:`--`
* :code:`\\q` quoted string
* :code:`\q` quoted string

View File

@@ -38,7 +38,7 @@ Minor Analysis Improvements
C/C++
"""""
* Added flow model for the :code:`SQLite` and :code:`OpenSSL` libraries. This may result in more alerts when running queries on codebases that use these libraries.
* Added flow models for the :code:`SQLite` and :code:`OpenSSL` libraries. This may result in more alerts when running queries on codebases that use these libraries.
C#
""

View File

@@ -50,7 +50,7 @@ New Queries
Golang
""""""
* Query (:code:`go/html-template-escaping-bypass-xss`) has been promoted to the main query suite. This query finds potential cross-site scripting (XSS) vulnerabilities when using the :code:`html/template` package, caused by user input being cast to a type which bypasses the HTML autoescaping. It was originally contributed to the experimental query pack by @gagliardetto in `https://github.com/github/codeql-go/pull/493 <https://github.com/github/codeql-go/pull/493>`_.
* Query (:code:`go/html-template-escaping-bypass-xss`) has been promoted to the main query suite. This query finds potential cross-site scripting (XSS) vulnerabilities when using the :code:`html/template` package, caused by user input being cast to a type which bypasses the HTML autoescaping. It was originally contributed to the experimental query pack by @gagliardetto in https://github.com/github/codeql-go/pull/493.
Language Libraries
------------------

View File

@@ -14,7 +14,7 @@ This is an overview of changes in the CodeQL CLI and relevant CodeQL query and l
Security Coverage
-----------------
CodeQL 2.22.1 runs a total of 449 security queries when configured with the Default suite (covering 165 CWE). The Extended suite enables an additional 129 queries (covering 33 more CWE).
CodeQL 2.22.1 runs a total of 476 security queries when configured with the Default suite (covering 166 CWE). The Extended suite enables an additional 129 queries (covering 32 more CWE). 27 security queries have been added with this release.
CodeQL CLI
----------
@@ -38,7 +38,7 @@ Minor Analysis Improvements
C/C++
"""""
* Added flow model for the following libraries: :code:`madler/zlib`, :code:`google/brotli`, :code:`libidn/libidn2`, :code:`libssh2/libssh2/`, :code:`nghttp2/nghttp2`, :code:`libuv/libuv/`, and :code:`curl/curl`. This may result in more alerts when running queries on codebases that use these libraries.
* Added flow models for the following libraries: :code:`madler/zlib`, :code:`google/brotli`, :code:`libidn/libidn2`, :code:`libssh2/libssh2`, :code:`nghttp2/nghttp2`, :code:`libuv/libuv`, and :code:`curl/curl`. This may result in more alerts when running queries on codebases that use these libraries.
C#
""

View File

@@ -0,0 +1,238 @@
.. _codeql-cli-2.22.2:
==========================
CodeQL 2.22.2 (2025-07-29)
==========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: none
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/code-scanning/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
Security Coverage
-----------------
CodeQL 2.22.2 runs a total of 474 security queries when configured with the Default suite (covering 166 CWE). The Extended suite enables an additional 130 queries (covering 32 more CWE).
CodeQL CLI
----------
Bug Fixes
~~~~~~~~~
* Fixes a bug in query suites where the :code:`version` property of an :code:`import` instruction was ignored. Previously, the following query suite would *not* resolve to :code:`v1.0.19` of :code:`codeql/csharp-queries`. Instead it would resolve to the latest version. This is now fixed and the resolve pack version would be :code:`v1.0.19`.
.. code-block:: text
- from: codeql/csharp-queries
import: codeql-suites/csharp-security-and-quality.qls
version: 1.0.19
Query Packs
-----------
Bug Fixes
~~~~~~~~~
C#
""
* :code:`web.config` and :code:`web.release.config` files are now recognized regardless of case. This means queries :code:`cs/web/debug-binary` and :code:`cs/web/missing-x-frame-options` may produce more results than before.
Breaking Changes
~~~~~~~~~~~~~~~~
JavaScript/TypeScript
"""""""""""""""""""""
* The :code:`Type` and :code:`Symbol` classes have been deprecated and will be empty in newly extracted databases, since the TypeScript extractor no longer populates them.
This is a breaking change for custom queries that explicitly relied on these classes.
Such queries will still compile, but with deprecation warnings, and may have different query results due to type information no longer being available.
We expect most custom queries will not be affected, however. If a custom query has no deprecation warnings, it should not be affected by this change.
Uses of :code:`getType()` should be rewritten to use the new :code:`getTypeBinding()` or :code:`getNameBinding()` APIs instead.
If the new API is not sufficient, please consider opening an issue in :code:`github/codeql` describing your use-case.
Major Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
JavaScript/TypeScript
"""""""""""""""""""""
* The TypeScript extractor no longer relies on the TypeScript compiler for extracting type information.
Instead, the information we need from types is now derived by an algorithm written in QL.
This results in more robust extraction with faster extraction times, in some cases significantly faster.
* Taint is now tracked through the React :code:`use` function.
* Parameters of React server functions, marked with the :code:`"use server"` directive, are now seen as taint sources.
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* Due to changes in the :code:`FunctionWithWrappers` library (:code:`semmle.code.cpp.security.FunctionWithWrappers`) the primary alert location generated by the queries :code:`cpp/path-injection`, :code:`cpp/sql-injection`, :code:`cpp/tainted-format-string`, and :code:`cpp/command-line-injection` may have changed.
* Added flow models for the Win32 API functions :code:`CreateThread`, :code:`CreateRemoteThread`, and :code:`CreateRemoteThreadEx`.
* Improved support for dataflow through function objects and lambda expressions.
* Added flow models for :code:`pthread_create` and :code:`std::thread`.
* The :code:`cpp/incorrect-string-type-conversion` query no longer alerts on incorrect type conversions that occur in unreachable code.
* Added flow models for the GNU C Library.
* Fixed a number of false positives and false negatives in :code:`cpp/global-use-before-init`. Note that this query is not part of any of the default query suites.
* The query :code:`cpp/sql-injection` now can be extended using the :code:`sql-injection` Models as Data (MaD) sink kind.
C#
""
* Explicitly added summary models for all overloads of :code:`System.Xml.XmlDictionaryReader.CreateBinaryReader`. Added models for some of the methods and properties in :code:`System.Runtime.Serialization.SerializationInfo` and :code:`System.Runtime.Serialization.SerializationInfoEnumerator`. Updated models for :code:`System.Text.Encoding.GetBytes`, :code:`System.Text.Encoding.GetChars` and the constructor for :code:`System.IO.MemoryStream`. This generally improves the library modelling and thus reduces the number of false negatives.
* Added explicit SQL injection Models as Data models for :code:`Microsoft.Data.SqlClient.SqlCommand` and :code:`Microsoft.Data.SqlClient.SqlDataAdapter`. This reduces false negatives for the query :code:`cs/sql-injection`.
Golang
""""""
* :code:`filepath.IsLocal` is now recognized as a sanitizer against path-traversal and related vulnerabilities.
Java/Kotlin
"""""""""""
* Java analysis of guards has been switched to use the new and improved shared guards library. This improves precision of a number of queries, in particular :code:`java/dereferenced-value-may-be-null`, which now has fewer false positives, and :code:`java/useless-null-check` and :code:`java/constant-comparison`, which gain additional true positives.
JavaScript/TypeScript
"""""""""""""""""""""
* Removed three queries from the JS qlpack, which have been superseded by newer queries that are part of the Actions qlpack:
* :code:`js/actions/pull-request-target` has been superseded by :code:`actions/untrusted-checkout/{medium,high,critical}`
* :code:`js/actions/actions-artifact-leak` has been superseded by :code:`actions/secrets-in-artifacts`
* :code:`js/actions/command-injection` has been superseded by :code:`actions/command-injection/{medium,critical}`
New Queries
~~~~~~~~~~~
Rust
""""
* Added a new query, :code:`rust/access-after-lifetime-ended`, for detecting pointer dereferences after the lifetime of the pointed-to object has ended.
Language Libraries
------------------
Bug Fixes
~~~~~~~~~
JavaScript/TypeScript
"""""""""""""""""""""
* The JavaScript extractor no longer ignores source files specified in the :code:`tsconfig.json` compiler options :code:`outDir` if doing so would result in excluding all source code.
Python
""""""
* The Python parser is now able to correctly parse expressions such as :code:`match[1]` and :code:`match()` where :code:`match` is not used as a keyword.
GitHub Actions
""""""""""""""
* The :code:`actions/artifact-poisoning/critical` and :code:`actions/artifact-poisoning/medium` queries now exclude artifacts downloaded to :code:`$[{ runner.temp }}` in addition to :code:`/tmp`.
Breaking Changes
~~~~~~~~~~~~~~~~
Ruby
""""
* Most classes and predicates in the AST, SSA, and control-flow-graph libraries are now annotated with :code:`overlay[local]`, in preparation for incremental analysis. This could result in compiler errors for custom queries if they extend these classes. To mitigate such errors, look for ways to restructure custom QL code so it doesn't depend on changing the behavior of standard-library classes.
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* The :code:`FunctionWithWrappers` library (:code:`semmle.code.cpp.security.FunctionWithWrappers`) no longer considers calls through function pointers as wrapper functions.
* The analysis of C/C++ code targeting 64-bit Arm platforms has been improved. This includes support for the Arm-specific builtin functions, support for the :code:`arm_neon.h` header and Neon vector types, and support for the :code:`fp8` scalar type. The :code:`arm_sve.h` header and scalable vectors are only partially supported at this point.
* Added support for :code:`__fp16 _Complex` and :code:`__bf16 _Complex` types
* Added :code:`sql-injection` sink models for the Oracle Call Interface (OCI) database library functions :code:`OCIStmtPrepare` and :code:`OCIStmtPrepare2`.
Golang
""""""
* Added models for the :code:`Head` function and the :code:`Client.Head` method, from the :code:`net/http` package, to the :code:`Http::ClientRequest` class. This means that they will be recognized as sinks for the query :code:`go/request-forgery` and the experimental query :code:`go/ssrf`.
* Previously, :code:`DefinedType.getBaseType` gave the underlying type. It now gives the right hand side of the type declaration, as the documentation indicated that it should.
Java/Kotlin
"""""""""""
* The qualifiers of a calls to :code:`readObject` on any classes that implement :code:`java.io.ObjectInput` are now recognised as sinks for :code:`java/unsafe-deserialization`. Previously this was only the case for classes which extend :code:`java.io.ObjectInputStream`.
JavaScript/TypeScript
"""""""""""""""""""""
* Enhanced modeling for the :code:`execa` library, adding support for command execution methods :code:`execaCommand`, :code:`execaCommandSync`, :code:`$`, and :code:`$.sync`, as well as file system operations through :code:`inputFile`, :code:`pipeStdout`, :code:`pipeAll`, and :code:`pipeStderr`.
Python
""""""
* Type annotations such as :code:`foo : Bar` are now treated by the call graph as an indication that :code:`foo` may be an instance of :code:`Bar`.
Rust
""""
* Type inference has been extended to support pattern matching.
* Call resolution for calls to associated functions has been improved, so it now disambiguates the targets based on type information at the call sites (either type information about the arguments or about the expected return types).
* Type inference has been improved for :code:`for` loops and range expressions, which improves call resolution and may ultimately lead to more query results.
* Implemented support for data flow through trait functions. For the purpose of data flow, calls to trait functions dispatch to all possible implementations.
* :code:`AssocItem` and :code:`ExternItem` are now proper subclasses of :code:`Item`.
* Added type inference for :code:`for` loops and array expressions.
Deprecated APIs
~~~~~~~~~~~~~~~
C/C++
"""""
* The :code:`UnknownDefaultLocation`, :code:`UnknownExprLocation`, and :code:`UnknownStmtLocation` classes have been deprecated. Use :code:`UnknownLocation` instead.
Golang
""""""
* The class :code:`BuiltinType` is now deprecated. Use the new replacement :code:`BuiltinTypeEntity` instead.
* The class :code:`DeclaredType` is now deprecated. Use the new replacement :code:`DeclaredTypeEntity` instead.
Java/Kotlin
"""""""""""
* The module :code:`semmle.code.java.frameworks.Castor` has been deprecated and will be removed in a future release.
* The module :code:`semmle.code.java.frameworks.JYaml` has been deprecated and will be removed in a future release.
* The classes :code:`UnsafeHessianInputReadObjectMethod` and :code:`BurlapInputReadObjectMethod` in the module :code:`semmle.code.java.frameworks.HessianBurlap` have been deprecated and will be removed in a future release.
* The class :code:`YamlBeansReaderReadMethod` in the module :code:`semmle.code.java.frameworks.YamlBeans` has been deprecated and will be removed in a future release.
* The class :code:`MethodApacheSerializationUtilsDeserialize` in the module :code:`semmle.code.java.frameworks.apache.Lang` has been deprecated and will be removed in a future release.
New Features
~~~~~~~~~~~~
C/C++
"""""
* Added a :code:`isFinalValueOfParameter` predicate to :code:`DataFlow::Node` which holds when a dataflow node represents the final value of an output parameter of a function.
C#
""
* Added a new predicate, :code:`getASuperType()`, to get a direct supertype of this type.
Java/Kotlin
"""""""""""
* You can now add sinks for the query "Deserialization of user-controlled data" (:code:`java/unsafe-deserialization`) using `data extensions <https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-java-and-kotlin/#extensible-predicates-used-to-create-custom-models-in-java-and-kotlin>`__ by extending :code:`sinkModel` and using the kind "unsafe-deserialization". The existing sinks that do not require extra logic to determine if they are unsafe are now defined in this way.
Shared Libraries
----------------
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Concepts
""""""""
* Initial release. Moves the shared concepts library into its own qlpack.

View File

@@ -0,0 +1,101 @@
.. _codeql-cli-2.22.3:
==========================
CodeQL 2.22.3 (2025-08-06)
==========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: none
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/code-scanning/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
Security Coverage
-----------------
CodeQL 2.22.3 runs a total of 476 security queries when configured with the Default suite (covering 169 CWE). The Extended suite enables an additional 130 queries (covering 32 more CWE). 2 security queries have been added with this release.
CodeQL CLI
----------
New Features
~~~~~~~~~~~~
* The :code:`codeql database cleanup` command now takes the :code:`--cache-cleanup=overlay` option, which trims the cache to just the data that will be useful when evaluating against an overlay.
Query Packs
-----------
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* The "Initialization code not run" query (:code:`cpp/initialization-not-run`) no longer reports an alert on static global variables that have no dereference.
Rust
""""
* Type inference now supports closures, calls to closures, and trait bounds using the :code:`FnOnce` trait.
* Type inference now supports trait objects, i.e., :code:`dyn Trait` types.
* Type inference now supports tuple types.
New Queries
~~~~~~~~~~~
Rust
""""
* Added a new query, :code:`rust/hard-coded-cryptographic-value`, for detecting use of hardcoded keys, passwords, salts and initialization vectors.
Language Libraries
------------------
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* The :code:`cpp/overrun-write` query now recognizes more bound checks and thus produces fewer false positives.
JavaScript/TypeScript
"""""""""""""""""""""
* The regular expressions in :code:`SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information.
Python
""""""
* The regular expressions in :code:`SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information.
Ruby
""""
* The regular expressions in :code:`SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information.
Swift
"""""
* The regular expressions in :code:`SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information.
Rust
""""
* Removed deprecated dataflow extensible predicates :code:`sourceModelDeprecated`, :code:`sinkModelDeprecated`, and :code:`summaryModelDeprecated`, along with their associated classes.
* The regular expressions in :code:`SensitiveDataHeuristics.qll` have been extended to find more instances of sensitive data such as secrets used in authentication, finance and health information, and device data. The heuristics have also been refined to find fewer false positive matches. This will improve results for queries related to sensitive information.
New Features
~~~~~~~~~~~~
C/C++
"""""
* Exposed various SSA-related classes (:code:`Definition`, :code:`PhiNode`, :code:`ExplicitDefinition`, :code:`DirectExplicitDefinition`, and :code:`IndirectExplicitDefinition`) which were previously only usable inside the internal dataflow directory.
Java/Kotlin
"""""""""""
* Kotlin versions up to 2.2.2\ *x* are now supported.

View File

@@ -11,6 +11,8 @@ A list of queries for each suite and language `is available here <https://docs.g
.. toctree::
:maxdepth: 1
codeql-cli-2.22.3
codeql-cli-2.22.2
codeql-cli-2.22.1
codeql-cli-2.22.0
codeql-cli-2.21.4

View File

@@ -17,7 +17,7 @@
.NET 5, .NET 6, .NET 7, .NET 8, .NET 9","``.sln``, ``.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.24", "Go 1.11 or more recent", ``.go``
Go (aka Golang), "Go up to 1.25", "Go 1.11 or more recent", ``.go``
Java,"Java 7 to 24 [6]_","javac (OpenJDK and Oracle JDK),
Eclipse compiler for Java (ECJ) [7]_",``.java``

View File

@@ -4,7 +4,7 @@ inputs:
go-test-version:
description: Which Go version to use for running the tests
required: false
default: "~1.24.0"
default: "~1.25.0"
run-code-checks:
description: Whether to run formatting, code and qhelp generation checks
required: false

View File

@@ -12,7 +12,7 @@ import (
)
var minGoVersion = util.NewSemVer("1.11")
var maxGoVersion = util.NewSemVer("1.24")
var maxGoVersion = util.NewSemVer("1.25")
type versionInfo struct {
goModVersion util.SemVer // The version of Go found in the go directive in the `go.mod` file.

View File

@@ -1,8 +1,8 @@
module github.com/github/codeql-go/extractor
go 1.24
go 1.25
toolchain go1.24.0
toolchain go1.25.0
// when updating this, run
// bazel run @rules_go//go -- mod tidy

View File

@@ -56,6 +56,17 @@ module AllocationSizeOverflow {
succ = c
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
exists(DataFlow::Node allocsz |
isSinkWithAllocationSize(sink, allocsz) and
result = allocsz.getLocation()
)
}
}
/** Tracks taint flow to find allocation-size overflows. */

View File

@@ -24,6 +24,8 @@ module CommandInjection {
}
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate observeDiffInformedIncrementalMode() { any() }
}
/**
@@ -80,6 +82,8 @@ module CommandInjection {
node instanceof Sanitizer or
node = any(ArgumentArrayWithDoubleDash array).getASanitizedElement()
}
predicate observeDiffInformedIncrementalMode() { any() }
}
/**

View File

@@ -186,6 +186,8 @@ private module UntrustedDataConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
predicate observeDiffInformedIncrementalMode() { any() }
}
/**

View File

@@ -30,6 +30,8 @@ module HardcodedCredentials {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate observeDiffInformedIncrementalMode() { any() }
}
/** Tracks taint flow for reasoning about hardcoded credentials. */

View File

@@ -440,6 +440,12 @@ private module ConversionWithoutBoundsCheckConfig implements DataFlow::StateConf
state2 = node2.(FlowStateTransformer).transform(state1) and
DataFlow::simpleLocalFlowStep(node1, node2, _)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getASuccessor().getLocation()
}
}
/**

View File

@@ -39,6 +39,10 @@ module InsecureRandomness {
n2.getType() instanceof IntegerType
)
}
predicate observeDiffInformedIncrementalMode() {
none() // Can't have accurate sink location override because of secondary use of `flowPath` in select.
}
}
/**

View File

@@ -22,6 +22,14 @@ module ReflectedXss {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
result = sink.(SharedXss::Sink).getAssociatedLoc().getLocation()
}
}
/** Tracks taint flow from untrusted data to XSS attack vectors. */

View File

@@ -31,6 +31,14 @@ module RequestForgery {
w.writesField(v.getAUse(), f, pred) and succ = v.getAUse()
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.getLocation()
or
result = sink.(Sink).getARequest().getLocation()
}
}
/** Tracks taint flow from untrusted data to request forgery attack vectors. */

View File

@@ -36,6 +36,10 @@ module SafeUrlFlow {
or
node instanceof SanitizerEdge
}
predicate observeDiffInformedIncrementalMode() {
none() // only used as secondary configuration
}
}
/** Tracks taint flow for reasoning about safe URLs. */

View File

@@ -128,6 +128,14 @@ module UnhandledFileCloseConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isWritableFileHandle(source, _) }
predicate isSink(DataFlow::Node sink) { isCloseSink(sink, _) }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) {
exists(DataFlow::CallNode openCall | result = openCall.getLocation() |
isWritableFileHandle(source, openCall)
)
}
}
/**

View File

@@ -68,6 +68,8 @@ module Config implements DataFlow::ConfigSig {
}
predicate isSink(DataFlow::Node sink) { writeIsSink(sink, _) }
predicate observeDiffInformedIncrementalMode() { any() }
}
/**

View File

@@ -123,6 +123,17 @@ module Config implements DataFlow::ConfigSig {
}
predicate isSink(DataFlow::Node sink) { sink instanceof OpenUrlRedirect::Sink }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) {
result = source.getLocation()
or
exists(DataFlow::Node check |
isCheckedSource(source, check) and
result = check.getLocation()
)
}
}
module Flow = TaintTracking::Global<Config>;

View File

@@ -116,6 +116,12 @@ private module BoolToGinSetCookieTrackingConfig implements DataFlow::ConfigSig {
)
)
}
predicate observeDiffInformedIncrementalMode() {
any() // Merged with other flows in CookieWithoutHttpOnly.ql
}
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
}
/**

View File

@@ -59,6 +59,14 @@ private module Config implements DataFlow::ConfigSig {
not c.isPotentialFalsePositive()
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(ComparisonExpr comp | result = comp.getLocation() | sink.asExpr() = comp.getAnOperand())
}
}
/**

View File

@@ -22,6 +22,10 @@ module Config implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) {
exists(ComparisonExpr c | c.getAnOperand() = sink.asExpr())
}
predicate observeDiffInformedIncrementalMode() {
none() // can't override the locations accurately because of secondary use of config.
}
}
/** Tracks taint flow for reasoning about conditional bypass. */

View File

@@ -30,6 +30,14 @@ module ServerSideRequestForgery {
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate isBarrierOut(DataFlow::Node node) { node instanceof SanitizerEdge }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.(Sink).getARequest().getLocation()
}
}
/** Tracks taint flow for reasoning about request forgery vulnerabilities. */

Some files were not shown because too many files have changed in this diff Show More