Merge branch 'main' into js/shared-dataflow-merge-main

This commit is contained in:
Asger F
2024-10-08 09:28:26 +02:00
2562 changed files with 73355 additions and 42975 deletions

View File

@@ -3,6 +3,7 @@ on:
push:
paths:
- "go/**"
- "shared/**"
- .github/workflows/go-tests.yml
- .github/actions/**
- codeql-workspace.yml
@@ -12,6 +13,7 @@ on:
pull_request:
paths:
- "go/**"
- "shared/**"
- .github/workflows/go-tests.yml
- .github/actions/**
- codeql-workspace.yml

60
Cargo.lock generated
View File

@@ -265,7 +265,7 @@ dependencies = [
"chalk-ir",
"ena",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"petgraph",
"rustc-hash",
"tracing",
@@ -374,6 +374,7 @@ dependencies = [
"clap",
"codeql-extractor",
"figment",
"itertools 0.13.0",
"log",
"num-traits",
"ra_ap_base_db",
@@ -381,6 +382,7 @@ dependencies = [
"ra_ap_hir_def",
"ra_ap_ide_db",
"ra_ap_load-cargo",
"ra_ap_parser",
"ra_ap_paths",
"ra_ap_project_model",
"ra_ap_syntax",
@@ -679,6 +681,16 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
[[package]]
name = "generate-schema"
version = "0.1.0"
dependencies = [
"itertools 0.10.5",
"proc-macro2",
"quote",
"ungrammar",
]
[[package]]
name = "getrandom"
version = "0.2.15"
@@ -848,6 +860,15 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.12.1"
@@ -857,6 +878,15 @@ dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.11"
@@ -1333,7 +1363,7 @@ checksum = "c7c38520eb4770af561c34b908431f4e548c3282093cf3daf3c6e566d99a2937"
dependencies = [
"arrayvec",
"either",
"itertools",
"itertools 0.12.1",
"ra_ap_base_db",
"ra_ap_cfg",
"ra_ap_hir_def",
@@ -1365,7 +1395,7 @@ dependencies = [
"fst",
"hashbrown 0.14.5",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"la-arena",
"ra-ap-rustc_abi",
"ra-ap-rustc_parse_format",
@@ -1395,7 +1425,7 @@ dependencies = [
"cov-mark",
"either",
"hashbrown 0.14.5",
"itertools",
"itertools 0.12.1",
"la-arena",
"ra_ap_base_db",
"ra_ap_cfg",
@@ -1430,7 +1460,7 @@ dependencies = [
"either",
"ena",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"la-arena",
"nohash-hasher",
"oorandom",
@@ -1467,7 +1497,7 @@ dependencies = [
"either",
"fst",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"line-index",
"memchr",
"nohash-hasher",
@@ -1513,7 +1543,7 @@ checksum = "82e6f24b61f1ef1f3a756493d1fb7e711b69b2e4d5f4746fcb959313dfd41471"
dependencies = [
"anyhow",
"crossbeam-channel",
"itertools",
"itertools 0.12.1",
"ra_ap_hir_expand",
"ra_ap_ide_db",
"ra_ap_intern",
@@ -1608,7 +1638,7 @@ checksum = "db83d1844c74b22c110c4b8e8f2519be2b1723964008527281a11c3398749756"
dependencies = [
"anyhow",
"cargo_metadata",
"itertools",
"itertools 0.12.1",
"la-arena",
"ra_ap_base_db",
"ra_ap_cfg",
@@ -1632,7 +1662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "370b302873eeafd07ccc6a714fc9395cae11e385955ccb78081093ee3b86f94e"
dependencies = [
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"lock_api",
"oorandom",
"parking_lot",
@@ -1679,7 +1709,7 @@ checksum = "bb63ff9d6b11b4553fc0835f16705975258905e3b1230fcf1ddbf24c46aff69d"
dependencies = [
"always-assert",
"crossbeam-channel",
"itertools",
"itertools 0.12.1",
"jod-thread",
"libc",
"miow",
@@ -1695,7 +1725,7 @@ dependencies = [
"cov-mark",
"either",
"indexmap 2.5.0",
"itertools",
"itertools 0.12.1",
"ra-ap-rustc_lexer",
"ra_ap_parser",
"ra_ap_stdx",
@@ -1729,7 +1759,7 @@ version = "0.0.232"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cb72ee1901baec556f4f2ef77e287d749ac0e973f063990672d6207b076aeac"
dependencies = [
"itertools",
"itertools 0.12.1",
"text-size",
]
@@ -2325,6 +2355,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "ungrammar"
version = "1.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f"
[[package]]
name = "unicode-ident"
version = "1.0.13"

View File

@@ -7,6 +7,7 @@ members = [
"ruby/extractor",
"rust/extractor",
"rust/extractor/macros",
"rust/generate-schema",
]
[patch.crates-io]

View File

@@ -61,6 +61,7 @@ r.from_cargo(
"//ruby/extractor:Cargo.toml",
"//rust/extractor:Cargo.toml",
"//rust/extractor/macros:Cargo.toml",
"//rust/generate-schema:Cargo.toml",
"//shared/tree-sitter-extractor:Cargo.toml",
],
)
@@ -127,6 +128,7 @@ use_repo(
"kotlin-compiler-1.9.20-Beta",
"kotlin-compiler-2.0.0-RC1",
"kotlin-compiler-2.0.20-Beta2",
"kotlin-compiler-2.1.0-Beta1",
"kotlin-compiler-embeddable-1.5.0",
"kotlin-compiler-embeddable-1.5.10",
"kotlin-compiler-embeddable-1.5.20",
@@ -140,6 +142,7 @@ use_repo(
"kotlin-compiler-embeddable-1.9.20-Beta",
"kotlin-compiler-embeddable-2.0.0-RC1",
"kotlin-compiler-embeddable-2.0.20-Beta2",
"kotlin-compiler-embeddable-2.1.0-Beta1",
"kotlin-stdlib-1.5.0",
"kotlin-stdlib-1.5.10",
"kotlin-stdlib-1.5.20",
@@ -153,6 +156,7 @@ use_repo(
"kotlin-stdlib-1.9.20-Beta",
"kotlin-stdlib-2.0.0-RC1",
"kotlin-stdlib-2.0.20-Beta2",
"kotlin-stdlib-2.1.0-Beta1",
)
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")

View File

@@ -57,10 +57,6 @@
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
],
"Model as Data Generation Java/C# - CaptureModels": [
"java/ql/src/utils/modelgenerator/internal/CaptureModels.qll",
"csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll"
],
"Sign Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
@@ -355,5 +351,9 @@
"Python model summaries test extension": [
"python/ql/test/library-tests/dataflow/model-summaries/InlineTaintTest.ext.yml",
"python/ql/test/library-tests/dataflow/model-summaries/NormalDataflowTest.ext.yml"
],
"Diagnostics.qll": [
"ruby/ql/lib/codeql/ruby/Diagnostics.qll",
"rust/ql/lib/codeql/rust/Diagnostics.qll"
]
}

View File

@@ -1,3 +1,7 @@
## 2.0.1
No user-facing changes.
## 2.0.0
### Breaking Changes

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 2.0.0
lastReleaseVersion: 2.0.1

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 2.0.1-dev
version: 2.0.2-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -500,6 +500,17 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* Gets the nearest enclosing AccessHolder.
*/
override AccessHolder getEnclosingAccessHolder() { result = this.getDeclaringType() }
/**
* Holds if this function has extraction errors that create an `ErrorExpr`.
*/
predicate hasErrors() {
exists(ErrorExpr e |
e.getEnclosingFunction() = this and
// Exclude the first allocator call argument because it is always extracted as `ErrorExpr`.
not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0))
)
}
}
pragma[noinline]
@@ -651,7 +662,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
/**
* Holds if this declaration is an implicit function declaration, that is,
* where a function is used before it is declared (under older C standards).
* where a function is used before it is declared (under older C standards,
* or when there were parse errors).
*/
predicate isImplicit() { fun_implicit(underlyingElement(this)) }

View File

@@ -39,8 +39,8 @@ class Type extends Locatable, @type {
/**
* Gets a specifier of this type, recursively looking through `typedef` and
* `decltype`. For example, in the context of `typedef const int *restrict
* t`, the type `volatile t` has specifiers `volatile` and `restrict` but not
* `decltype`. For example, in the context of `typedef const int *restrict t`,
* the type `volatile t` has specifiers `volatile` and `restrict` but not
* `const` since the `const` is attached to the type being pointed to rather
* than the pointer itself.
*/

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -546,7 +546,7 @@ module ProductFlow {
Flow1::PathGraph::edges(pred1, succ1, _, _) and
exists(ReturnKindExt returnKind |
succ1.getNode() = returnKind.getAnOutNode(call) and
paramReturnNode(_, pred1.asParameterReturnNode(), _, returnKind)
returnKind = getParamReturnPosition(_, pred1.asParameterReturnNode()).getKind()
)
}
@@ -574,7 +574,7 @@ module ProductFlow {
Flow2::PathGraph::edges(pred2, succ2, _, _) and
exists(ReturnKindExt returnKind |
succ2.getNode() = returnKind.getAnOutNode(call) and
paramReturnNode(_, pred2.asParameterReturnNode(), _, returnKind)
returnKind = getParamReturnPosition(_, pred2.asParameterReturnNode()).getKind()
)
}

View File

@@ -118,19 +118,34 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
/**
* Gets the position of the first format argument, corresponding with
* the first format specifier in the format string.
* the first format specifier in the format string. We ignore all
* implicit function definitions.
*/
int getFirstFormatArgumentIndex() {
result = this.getNumberOfParameters() and
// the formatting function either has a definition in the snapshot, or all
// The formatting function either has a definition in the snapshot, or all
// `DeclarationEntry`s agree on the number of parameters (otherwise we don't
// really know the correct number)
(
this.hasDefinition()
or
forall(FunctionDeclarationEntry fde | fde = this.getADeclarationEntry() |
result = fde.getNumberOfParameters()
)
if this.hasDefinition()
then result = this.getDefinition().getNumberOfParameters()
else result = this.getNumberOfExplicitParameters()
}
/**
* Gets a non-implicit function declaration entry.
*/
private FunctionDeclarationEntry getAnExplicitDeclarationEntry() {
result = this.getADeclarationEntry() and
not result.isImplicit()
}
/**
* Gets the number of parameters, excluding any parameters that have been defined
* from implicit function declarations. If there is some inconsistency in the number
* of parameters, then don't return anything.
*/
private int getNumberOfExplicitParameters() {
forex(FunctionDeclarationEntry fde | fde = this.getAnExplicitDeclarationEntry() |
result = fde.getNumberOfParameters()
)
}

View File

@@ -160,6 +160,26 @@ private module InvalidPointerToDerefBarrier {
}
}
/**
* BEWARE: This configuration uses an unrestricted sink, so accessing its full
* flow computation or any stages beyond the first 2 will likely diverge.
* Stage 1 will still be fast and we use it to restrict the subsequent sink
* computation.
*/
private module InvalidPointerReachesConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, _, source) }
predicate isSink(DataFlow::Node sink) { any() }
predicate isBarrier(DataFlow::Node node) { InvalidPointerToDerefConfig::isBarrier(node) }
int fieldFlowBranchLimit() { result = invalidPointerToDereferenceFieldFlowBranchLimit() }
}
private module InvalidPointerReachesFlow = DataFlow::Global<InvalidPointerReachesConfig>;
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
/**
* A configuration to track flow from a pointer-arithmetic operation found
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
@@ -173,8 +193,13 @@ private module InvalidPointerToDerefConfig implements DataFlow::StateConfigSig {
invalidPointerToDerefSource(_, pai, source)
}
pragma[inline]
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _, _) }
predicate isSink(DataFlow::Node sink) {
exists(DataFlowImplCommon::NodeEx n |
InvalidPointerReachesFlow::Stages::Stage1::sinkNode(n, _) and
n.asNode() = sink and
isInvalidPointerDerefSink(sink, _, _, _, _)
)
}
predicate isSink(DataFlow::Node sink, FlowState pai) { none() }

View File

@@ -72,7 +72,6 @@ module FlowFromFree<FlowFromFreeParamSig P> {
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, _, state, _) }
pragma[inline]
predicate isSink(DataFlow::Node sink, FlowState state) {
exists(Expr e, DataFlow::Node source, DeallocationExpr dealloc |
P::isSink(sink, e) and

View File

@@ -57,5 +57,5 @@ where
not declarationHasSideEffects(v) and
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
not v.getAnAttribute().getName() = "unused" and
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
not f.hasErrors() // Unextracted expressions may use `v`
select v, "Variable " + v.getName() + " is not used."

View File

@@ -1,9 +1,15 @@
## 1.2.4
### Minor Analysis Improvements
* Fixed false positives in the `cpp/wrong-number-format-arguments` ("Too few arguments to formatting function") query when the formatting function has been declared implicitly.
## 1.2.3
### Minor Analysis Improvements
* Removed false positives caused by buffer accesses in unreachable code.
* Removed false positives caused by inconsistent type checking.
* Removed false positives caused by buffer accesses in unreachable code
* Removed false positives caused by inconsistent type checking
* Add modeling of C functions that don't throw, thereby increasing the precision of the `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query. The query now produces additional true positives.
## 1.2.2

View File

@@ -29,7 +29,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
override predicate isSource(Instruction source) {
exists(Function func |
// Rule out FPs caused by extraction errors.
not any(ErrorExpr e).getEnclosingFunction() = func and
not func.hasErrors() and
not intentionallyReturnsStackPointer(func) and
func = source.getEnclosingFunction()
|

View File

@@ -65,6 +65,7 @@ predicate isSinkImpl(Instruction sink, VariableAccess va) {
exists(LoadInstruction load |
va = load.getUnconvertedResultExpression() and
not va = commonException() and
not va.getTarget().(LocalVariable).getFunction().hasErrors() and
sink = load.getSourceValue()
)
}

View File

@@ -24,7 +24,7 @@ predicate instructionHasVariable(VariableAddressInstruction vai, StackVariable v
// Pointer-to-member types aren't properly handled in the dbscheme.
not vai.getResultType() instanceof PointerToMemberType and
// Rule out FPs caused by extraction errors.
not any(ErrorExpr e).getEnclosingFunction() = f
not f.hasErrors()
}
/**

View File

@@ -13,23 +13,85 @@
*/
import cpp
import semmle.code.cpp.controlflow.Guards
class WideCharPointerType extends PointerType {
WideCharPointerType() { this.getBaseType() instanceof WideCharType }
}
/**
* Given type `t`, recurses through and returns all
* intermediate base types, including `t`.
*/
Type getABaseType(Type t) {
result = t
or
result = getABaseType(t.(DerivedType).getBaseType())
or
result = getABaseType(t.(TypedefType).getBaseType())
}
/**
* A type that may also be `CharPointerType`, but that are likely used as arbitrary buffers.
*/
class UnlikelyToBeAStringType extends Type {
UnlikelyToBeAStringType() {
this.(PointerType).getBaseType().(CharType).isUnsigned() or
this.(PointerType).getBaseType().getName().toLowerCase().matches("%byte") or
this.getName().toLowerCase().matches("%byte") or
this.(PointerType).getBaseType().hasName("uint8_t")
exists(Type targ | getABaseType(this) = targ |
// NOTE: not using CharType isUnsigned, but rather look for any explicitly declared unsigned
// char types. Assuming these are used for buffers, not strings.
targ.(CharType).getName().toLowerCase().matches("unsigned%") or
targ.getName().toLowerCase().matches(["uint8_t", "%byte%"])
)
}
}
// Types that can be wide depending on the UNICODE macro
// see https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
class UnicodeMacroDependentWidthType extends Type {
UnicodeMacroDependentWidthType() {
exists(Type targ | getABaseType(this) = targ |
targ.getName() in [
"LPCTSTR",
"LPTSTR",
"PCTSTR",
"PTSTR",
"TBYTE",
"TCHAR"
]
)
}
}
class UnicodeMacro extends Macro {
UnicodeMacro() { this.getName().toLowerCase().matches("%unicode%") }
}
class UnicodeMacroInvocation extends MacroInvocation {
UnicodeMacroInvocation() { this.getMacro() instanceof UnicodeMacro }
}
/**
* Holds when a expression whose type is UnicodeMacroDependentWidthType and
* is observed to be guarded by a check involving a bitwise-and operation
* with a UnicodeMacroInvocation.
* Such expressions are assumed to be checked dynamically, i.e.,
* the flag would indicate if UNICODE typing is set correctly to allow
* or disallow a widening cast.
*/
predicate isLikelyDynamicallyChecked(Expr e) {
e.getType() instanceof UnicodeMacroDependentWidthType and
exists(GuardCondition gc, BitwiseAndExpr bai, UnicodeMacroInvocation umi |
bai.getAnOperand() = umi.getExpr()
|
// bai == 0 is false when reaching `e.getBasicBlock()`.
// That is, bai != 0 when reaching `e.getBasicBlock()`.
gc.ensuresEq(bai, 0, e.getBasicBlock(), false)
or
// bai == k and k != 0 is true when reaching `e.getBasicBlock()`.
gc.ensuresEq(bai, any(int k | k != 0), e.getBasicBlock(), true)
)
}
from Expr e1, Cast e2
where
e2 = e1.getConversion() and
@@ -42,7 +104,11 @@ where
not e1.getType() instanceof UnlikelyToBeAStringType and
// Avoid castings from 'new' expressions as typically these will be safe
// Example: `__Type* ret = reinterpret_cast<__Type*>(New(m_pmo) char[num * sizeof(__Type)]);`
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1)
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1) and
// Avoid cases where the cast is guarded by a check to determine if
// unicode encoding is enabled in such a way to disallow the dangerous cast
// at runtime.
not isLikelyDynamicallyChecked(e1)
select e1,
"Conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
". Use of invalid string can lead to undefined behavior."

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to detect byte arrays.
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to recognize dynamic checks prior to possible dangerous widening.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Fixed false positives in the `cpp/uninitialized-local` ("Potentially uninitialized local variable") query if there are extraction errors in the function.

View File

@@ -0,0 +1,5 @@
## 1.2.4
### Minor Analysis Improvements
* Fixed false positives in the `cpp/wrong-number-format-arguments` ("Too few arguments to formatting function") query when the formatting function has been declared implicitly.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.2.3
lastReleaseVersion: 1.2.4

View File

@@ -0,0 +1,34 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
Disabling verification of the SSL certificate allows man-in-the-middle attacks. A SSL
connection is vulnerable to man-in-the-middle attacks if the certification is not checked
properly. If the peer or the host's certificate verification is not verified, the underlying
SSL communication is insecure.</p>
</overview>
<recommendation>
<p>It is recommended that all communications be done post verification of the host as well as
the
peer.</p>
</recommendation>
<example>
<p>The following snippet disables certification verification by setting the value of <code>
CURLOPT_SSL_VERIFYHOST</code> and <code>CURLOPT_SSL_VERIFYHOST</code> to <code>0</code>:</p>
<sample src="CurlSSLBad.cpp" />
<p>This is bad as the certificates are not verified any more. This can be easily fixed by
setting the values of the options to <code>2</code>. </p>
<sample src="CurlSSLGood.cpp" />
</example>
<references>
<li> Curl Documentation:<a href="https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html">
CURLOPT_SSL_VERIFYHOST</a></li>
<li> Curl Documentation:<a href="https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html">
CURLOPT_SSL_VERIFYPEER</a></li>
<li> Related CVE: <a href="https://github.com/advisories/GHSA-5r3h-c3r7-9w4h"> CVE-2022-33684</a></li>
<li> Related security advisory: <a
href="https://huntr.com/bounties/42325662-6329-4e04-875a-49e2f5d69f78">
openframeworks/openframeworks
</a></li>
</references>
</qhelp>

View File

@@ -0,0 +1,39 @@
/**
* @name Disabled certifcate verification
* @description Disabling SSL certificate verification of host or peer could expose the communication to man-in-the-middle(MITM) attacks.
* @kind problem
* @problem.severity warning
* @id cpp/curl-disabled-ssl
* @tags security
* external/cwe/cwe-295
*/
import cpp
import semmle.code.cpp.dataflow.new.TaintTracking
/** Models the `curl_easy_setopt` function call */
private class CurlSetOptCall extends FunctionCall {
CurlSetOptCall() {
exists(FunctionCall fc, Function f |
f.hasGlobalOrStdName("curl_easy_setopt") and
fc.getTarget() = f
|
this = fc
)
}
}
/** Models an access to any enum constant which could affect SSL verification */
private class CurlVerificationConstant extends EnumConstantAccess {
CurlVerificationConstant() {
exists(EnumConstant e | e.getName() = ["CURLOPT_SSL_VERIFYHOST", "CURLOPT_SSL_VERIFYPEER"] |
e.getAnAccess() = this
)
}
}
from CurlSetOptCall c
where
c.getArgument(1) = any(CurlVerificationConstant v) and
c.getArgument(2).getValue() = "0"
select c, "This call disables Secure Socket Layer and could potentially lead to MITM attacks"

View File

@@ -0,0 +1,9 @@
string host = "codeql.com"
void bad(void) {
std::unique_ptr<CURL, void(*)(CURL*)> curl =
std::unique_ptr<CURL, void(*)(CURL*)>(curl_easy_init(), curl_easy_cleanup);
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl.get(), CURLOPT_URL, host.c_str());
curl_easy_perform(curl.get());
}

View File

@@ -0,0 +1,9 @@
string host = "codeql.com"
void good(void) {
std::unique_ptr<CURL, void(*)(CURL*)> curl =
std::unique_ptr<CURL, void(*)(CURL*)>(curl_easy_init(), curl_easy_cleanup);
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 2);
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 2);
curl_easy_setopt(curl.get(), CURLOPT_URL, host.c_str());
curl_easy_perform(curl.get());
}

View File

@@ -49,7 +49,7 @@ predicate functionsMissingReturnStmt(Function f, ControlFlowNode blame) {
predicate functionImperfectlyExtracted(Function f) {
exists(CompilerError e | f.getBlock().getLocation().subsumes(e.getLocation()))
or
exists(ErrorExpr ee | ee.getEnclosingFunction() = f)
f.hasErrors()
or
count(f.getType()) > 1
or

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.2.4-dev
version: 1.2.5-dev
groups:
- cpp
- queries

View File

@@ -0,0 +1,43 @@
#include "../../../../../library-tests/string_concat/stl.h"
namespace std{
struct CURL {};
typedef CURL curl;
enum curl_constant{
CURLOPT_URL,
CURLOPT_SSL_VERIFYHOST,
CURLOPT_SSL_VERIFYPEER
};
CURL *curl_easy_init();
void curl_easy_cleanup(CURL *handle);
void curl_easy_perform(CURL *handle);
void curl_easy_setopt(CURL *handle, curl_constant param, int p);
void curl_easy_setopt(CURL *handle, curl_constant param, char* p);
}
using namespace std;
char host[] = "codeql.com";
void bad(void) {
std::unique_ptr<CURL> curl = std::unique_ptr<CURL>(curl_easy_init());
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl.get(), CURLOPT_URL, host);
curl_easy_perform(curl.get());
}
void good(void) {
std::unique_ptr<CURL> curl = std::unique_ptr<CURL>(curl_easy_init());
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 2);
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 2);
curl_easy_setopt(curl.get(), CURLOPT_URL, host);
curl_easy_perform(curl.get());
}
int main(int c, char** argv){
bad();
good();
}

View File

@@ -0,0 +1,2 @@
| CurlSSL.cpp:25:2:25:17 | call to curl_easy_setopt | This call disables Secure Socket Layer and could potentially lead to MITM attacks |
| CurlSSL.cpp:26:2:26:17 | call to curl_easy_setopt | This call disables Secure Socket Layer and could potentially lead to MITM attacks |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-295/CurlSSL.ql

View File

@@ -3,20 +3,20 @@ failures
edges
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:10 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:2 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:2 Sink:MaD:6 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:2 Sink:MaD:6 |
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:10 |
| test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | test.cpp:4:5:4:11 | [summary] to write: ReturnValue in ymlStep | provenance | MaD:644 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:7:10:7:18 | call to ymlSource | provenance | Src:MaD:642 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:643 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:643 |
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:13:18:13:18 | x | provenance | |
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:13:10:13:16 | call to ymlStep | provenance | |
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:643 |
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:643 |
| test.cpp:13:18:13:18 | x | test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | provenance | |
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep | provenance | MaD:644 |
nodes

View File

@@ -1,4 +1,4 @@
| c.c | library-tests/files/c.c | CFile, MetricFile | C | | |
| files1.cpp | library-tests/files/files1.cpp | CppFile, MetricFile | C++ | swap | t |
| files1.h | library-tests/files/files1.h | HeaderFile, MetricFile | | swap | |
| files2.cpp | library-tests/files/files2.cpp | CppFile, MetricFile | C++ | g | x, y |
| c.c | c.c | CFile, MetricFile | C | | |
| files1.cpp | files1.cpp | CppFile, MetricFile | C++ | swap | t |
| files1.h | files1.h | HeaderFile, MetricFile | | swap | |
| files2.cpp | files2.cpp | CppFile, MetricFile | C++ | g | x, y |

View File

@@ -2,25 +2,168 @@
| file://:0:0:0:0 | (unnamed parameter 0) | false |
| file://:0:0:0:0 | __super | false |
| file://:0:0:0:0 | __va_list_tag | false |
| file://:0:0:0:0 | decltype([...](...){...}) | false |
| file://:0:0:0:0 | operator= | false |
| file://:0:0:0:0 | operator= | false |
| test.cpp:0:0:0:0 | test.cpp | false |
| test.cpp:2:1:2:61 | #define FOO class S{int i; void f(void) { int j; return; } }; | false |
| test.cpp:2:1:2:68 | #define CLASS_DECL class S{int i; void f(void) { int j; return; } }; | false |
| test.cpp:4:1:4:1 | S | false |
| test.cpp:4:1:4:1 | declaration of S | false |
| test.cpp:4:1:4:1 | declaration of operator= | false |
| test.cpp:4:1:4:1 | declaration of operator= | false |
| test.cpp:4:1:4:1 | operator= | false |
| test.cpp:4:1:4:1 | operator= | false |
| test.cpp:4:1:4:3 | FOO | false |
| test.cpp:4:1:4:3 | S | false |
| test.cpp:4:1:4:3 | declaration | true |
| test.cpp:4:1:4:3 | definition of S | true |
| test.cpp:4:1:4:3 | definition of f | true |
| test.cpp:4:1:4:3 | definition of i | true |
| test.cpp:4:1:4:3 | definition of j | true |
| test.cpp:4:1:4:3 | f | false |
| test.cpp:4:1:4:3 | i | false |
| test.cpp:4:1:4:3 | j | true |
| test.cpp:4:1:4:3 | return ... | true |
| test.cpp:4:1:4:3 | { ... } | true |
| test.cpp:4:1:4:10 | CLASS_DECL | false |
| test.cpp:4:1:4:10 | S | false |
| test.cpp:4:1:4:10 | declaration | true |
| test.cpp:4:1:4:10 | definition of S | true |
| test.cpp:4:1:4:10 | definition of f | true |
| test.cpp:4:1:4:10 | definition of i | true |
| test.cpp:4:1:4:10 | definition of j | true |
| test.cpp:4:1:4:10 | f | false |
| test.cpp:4:1:4:10 | i | false |
| test.cpp:4:1:4:10 | j | true |
| test.cpp:4:1:4:10 | return ... | true |
| test.cpp:4:1:4:10 | { ... } | true |
| test.cpp:6:1:6:42 | #define FUNCTION_DECL void f1() { int k; } | false |
| test.cpp:8:1:8:13 | FUNCTION_DECL | false |
| test.cpp:8:1:8:13 | declaration | true |
| test.cpp:8:1:8:13 | definition of f1 | true |
| test.cpp:8:1:8:13 | definition of k | true |
| test.cpp:8:1:8:13 | f1 | false |
| test.cpp:8:1:8:13 | k | true |
| test.cpp:8:1:8:13 | return ... | true |
| test.cpp:8:1:8:13 | { ... } | true |
| test.cpp:10:1:10:33 | #define VARIABLE_DECL int v1 = 1; | false |
| test.cpp:12:1:12:13 | 1 | true |
| test.cpp:12:1:12:13 | VARIABLE_DECL | false |
| test.cpp:12:1:12:13 | definition of v1 | true |
| test.cpp:12:1:12:13 | initializer for v1 | true |
| test.cpp:12:1:12:13 | v1 | true |
| test.cpp:14:1:14:35 | #define TYPE_DECL_1 typedef int t1; | false |
| test.cpp:16:1:16:11 | TYPE_DECL_1 | false |
| test.cpp:16:1:16:11 | declaration of t1 | true |
| test.cpp:16:1:16:11 | t1 | false |
| test.cpp:18:1:18:35 | #define TYPE_DECL_2 using t2 = int; | false |
| test.cpp:20:1:20:11 | TYPE_DECL_2 | false |
| test.cpp:20:1:20:11 | declaration of t2 | true |
| test.cpp:20:1:20:11 | t2 | false |
| test.cpp:22:1:22:47 | #define NAMESPACE_DECL namespace ns { int v2; } | false |
| test.cpp:24:1:24:14 | NAMESPACE_DECL | false |
| test.cpp:24:1:24:14 | definition of v2 | true |
| test.cpp:24:1:24:14 | ns | false |
| test.cpp:24:1:24:14 | ns | false |
| test.cpp:24:1:24:14 | v2 | true |
| test.cpp:26:1:26:43 | #define USING_NAMESPACE using namespace ns; | false |
| test.cpp:28:1:28:34 | #define ENUM_CONSTANT enum_element | false |
| test.cpp:30:12:30:21 | definition of enum_class | false |
| test.cpp:30:12:30:21 | enum_class | false |
| test.cpp:30:25:30:37 | ENUM_CONSTANT | false |
| test.cpp:30:25:30:37 | enum_element | false |
| test.cpp:32:1:32:41 | #define USING_ENUM using enum enum_class; | false |
| test.cpp:34:1:34:10 | USING_ENUM | false |
| test.cpp:34:1:34:10 | using enum enum_class | false |
| test.cpp:36:1:36:48 | #define STATIC_ASSERT static_assert(1 == 1, ""); | false |
| test.cpp:38:1:38:13 | 1 | true |
| test.cpp:38:1:38:13 | 1 | true |
| test.cpp:38:1:38:13 | ... == ... | true |
| test.cpp:38:1:38:13 | STATIC_ASSERT | false |
| test.cpp:38:1:38:13 | static_assert(..., "") | false |
| test.cpp:40:1:40:42 | #define ATTRIBUTE [[nodiscard("reason1")]] | false |
| test.cpp:42:1:42:9 | ATTRIBUTE | false |
| test.cpp:42:1:42:9 | nodiscard | false |
| test.cpp:42:1:42:9 | reason1 | false |
| test.cpp:42:1:42:9 | reason1 | true |
| test.cpp:43:5:43:6 | declaration of f2 | false |
| test.cpp:43:5:43:6 | f2 | false |
| test.cpp:45:1:45:31 | #define ATTRIBUTE_ARG "reason2" | false |
| test.cpp:47:3:47:11 | nodiscard | false |
| test.cpp:47:13:47:25 | ATTRIBUTE_ARG | false |
| test.cpp:47:13:47:25 | reason2 | false |
| test.cpp:47:13:47:25 | reason2 | true |
| test.cpp:48:5:48:6 | declaration of f3 | false |
| test.cpp:48:5:48:6 | f3 | false |
| test.cpp:50:1:50:16 | #define TYPE int | false |
| test.cpp:52:1:52:4 | TYPE | false |
| test.cpp:52:6:52:7 | definition of v3 | true |
| test.cpp:52:6:52:7 | v3 | true |
| test.cpp:52:11:52:11 | 1 | false |
| test.cpp:52:11:52:11 | initializer for v3 | false |
| test.cpp:54:1:54:29 | #define DERIVATION : public S | false |
| test.cpp:56:7:56:7 | T | false |
| test.cpp:56:7:56:7 | T | false |
| test.cpp:56:7:56:7 | declaration of T | false |
| test.cpp:56:7:56:7 | declaration of operator= | false |
| test.cpp:56:7:56:7 | declaration of operator= | false |
| test.cpp:56:7:56:7 | definition of T | false |
| test.cpp:56:7:56:7 | operator= | false |
| test.cpp:56:7:56:7 | operator= | false |
| test.cpp:56:9:56:18 | DERIVATION | false |
| test.cpp:56:9:56:18 | derivation | false |
| test.cpp:58:1:58:31 | #define FRIEND friend int f3(); | false |
| test.cpp:60:7:60:7 | U | false |
| test.cpp:60:7:60:7 | declaration of operator= | false |
| test.cpp:60:7:60:7 | declaration of operator= | false |
| test.cpp:60:7:60:7 | definition of U | false |
| test.cpp:60:7:60:7 | operator= | false |
| test.cpp:60:7:60:7 | operator= | false |
| test.cpp:61:3:61:8 | FRIEND | false |
| test.cpp:61:3:61:8 | U's friend | false |
| test.cpp:64:1:64:24 | #define NAME_QUAL_1 ns:: | false |
| test.cpp:66:1:66:22 | #define NAME_QUAL_2 ns | false |
| test.cpp:68:1:68:19 | #define LOCAL_VAR m | false |
| test.cpp:70:6:70:7 | definition of f4 | false |
| test.cpp:70:6:70:7 | f4 | false |
| test.cpp:70:11:76:1 | { ... } | false |
| test.cpp:71:5:71:8 | ns:: | false |
| test.cpp:71:5:71:15 | NAME_QUAL_1 | false |
| test.cpp:71:5:71:18 | v2 | false |
| test.cpp:71:5:71:19 | ExprStmt | false |
| test.cpp:72:5:72:8 | ns:: | false |
| test.cpp:72:5:72:15 | NAME_QUAL_2 | false |
| test.cpp:72:5:72:21 | v2 | false |
| test.cpp:72:5:72:22 | ExprStmt | false |
| test.cpp:73:5:73:23 | declaration | false |
| test.cpp:73:9:73:17 | LOCAL_VAR | false |
| test.cpp:73:9:73:17 | definition of m | true |
| test.cpp:73:9:73:17 | m | true |
| test.cpp:73:20:73:22 | 42 | false |
| test.cpp:73:20:73:22 | initializer for m | false |
| test.cpp:74:5:74:41 | declaration | false |
| test.cpp:74:10:74:10 | definition of l | false |
| test.cpp:74:10:74:10 | l | false |
| test.cpp:74:13:74:40 | [...](...){...} | false |
| test.cpp:74:13:74:40 | initializer for l | false |
| test.cpp:74:13:74:40 | {...} | false |
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
| test.cpp:74:14:74:14 | declaration of (unnamed constructor) | false |
| test.cpp:74:14:74:14 | declaration of (unnamed constructor) | false |
| test.cpp:74:14:74:14 | definition of (unnamed constructor) | false |
| test.cpp:74:14:74:14 | definition of operator= | false |
| test.cpp:74:14:74:14 | operator= | false |
| test.cpp:74:15:74:15 | definition of m | false |
| test.cpp:74:15:74:15 | m | false |
| test.cpp:74:15:74:15 | m | false |
| test.cpp:74:15:74:23 | LOCAL_VAR | false |
| test.cpp:74:15:74:23 | m | true |
| test.cpp:74:25:74:25 | definition of operator() | false |
| test.cpp:74:25:74:25 | operator() | false |
| test.cpp:74:28:74:40 | { ... } | false |
| test.cpp:74:30:74:38 | return ... | false |
| test.cpp:74:37:74:37 | (int)... | false |
| test.cpp:75:5:75:5 | (const lambda [] type at line 74, col. 14)... | false |
| test.cpp:75:5:75:5 | l | false |
| test.cpp:75:5:75:8 | ExprStmt | false |
| test.cpp:75:6:75:6 | call to operator() | false |
| test.cpp:76:1:76:1 | return ... | false |
| test.cpp:78:1:78:15 | #define ID(x) x | false |
| test.cpp:79:1:79:23 | #define NESTED(x) ID(x) | false |
| test.cpp:80:5:80:6 | definition of v4 | false |
| test.cpp:80:5:80:6 | v4 | false |
| test.cpp:80:10:80:18 | ID(x) | false |
| test.cpp:80:10:80:18 | NESTED(x) | false |
| test.cpp:80:17:80:17 | 1 | true |
| test.cpp:80:17:80:17 | initializer for v4 | true |
| test.cpp:82:1:82:39 | // semmle-extractor-options: -std=c++20 | false |

View File

@@ -1,5 +1,82 @@
#define FOO class S{int i; void f(void) { int j; return; } };
#define CLASS_DECL class S{int i; void f(void) { int j; return; } };
FOO
CLASS_DECL
#define FUNCTION_DECL void f1() { int k; }
FUNCTION_DECL
#define VARIABLE_DECL int v1 = 1;
VARIABLE_DECL
#define TYPE_DECL_1 typedef int t1;
TYPE_DECL_1
#define TYPE_DECL_2 using t2 = int;
TYPE_DECL_2
#define NAMESPACE_DECL namespace ns { int v2; }
NAMESPACE_DECL
#define USING_NAMESPACE using namespace ns;
#define ENUM_CONSTANT enum_element
enum class enum_class { ENUM_CONSTANT };
#define USING_ENUM using enum enum_class;
USING_ENUM
#define STATIC_ASSERT static_assert(1 == 1, "");
STATIC_ASSERT
#define ATTRIBUTE [[nodiscard("reason1")]]
ATTRIBUTE
int f2();
#define ATTRIBUTE_ARG "reason2"
[[nodiscard(ATTRIBUTE_ARG)]]
int f3();
#define TYPE int
TYPE v3 = 1;
#define DERIVATION : public S
class T DERIVATION {};
#define FRIEND friend int f3();
class U {
FRIEND
};
#define NAME_QUAL_1 ns::
#define NAME_QUAL_2 ns
#define LOCAL_VAR m
void f4() {
NAME_QUAL_1 v2;
NAME_QUAL_2 :: v2;
int LOCAL_VAR = 42;
auto l = [LOCAL_VAR]() { return m; };
l();
}
#define ID(x) x
#define NESTED(x) ID(x)
int v4 = NESTED(1);
// semmle-extractor-options: -std=c++20

View File

@@ -1,6 +1,6 @@
| containserror.cpp:0:0:0:0 | containserror.cpp | query-tests/Diagnostics/containserror.cpp | fromSource, normalTermination |
| containswarning.cpp:0:0:0:0 | containswarning.cpp | query-tests/Diagnostics/containswarning.cpp | fromSource, normalTermination |
| doesnotcompile.cpp:0:0:0:0 | doesnotcompile.cpp | query-tests/Diagnostics/doesnotcompile.cpp | ExtractionProblem (severity 1), fromSource, normalTermination |
| containserror.cpp:0:0:0:0 | containserror.cpp | containserror.cpp | fromSource, normalTermination |
| containswarning.cpp:0:0:0:0 | containswarning.cpp | containswarning.cpp | fromSource, normalTermination |
| doesnotcompile.cpp:0:0:0:0 | doesnotcompile.cpp | doesnotcompile.cpp | ExtractionProblem (severity 1), fromSource, normalTermination |
| file://:0:0:0:0 | | | |
| header.h:0:0:0:0 | header.h | query-tests/Diagnostics/header.h | fromSource |
| successful.cpp:0:0:0:0 | successful.cpp | query-tests/Diagnostics/successful.cpp | fromSource, normalTermination |
| header.h:0:0:0:0 | header.h | header.h | fromSource |
| successful.cpp:0:0:0:0 | successful.cpp | successful.cpp | fromSource, normalTermination |

View File

@@ -1,16 +1,16 @@
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:9:5:9:10 | call to proto6 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:9:5:9:10 | call to proto6 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:10:5:10:10 | call to proto7 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:10:5:10:10 | call to proto7 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:12:5:12:10 | call to proto9 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:12:5:12:10 | call to proto9 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:13:5:13:11 | call to proto10 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:13:5:13:11 | call to proto10 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:14:5:14:11 | call to proto11 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:14:5:14:11 | call to proto11 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:16:5:16:11 | call to proto13 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:16:5:16:11 | call to proto13 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user1.c:9:5:9:6 | call to f1 | query-tests/Documentation/DocumentApi/user1.c |
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user2.c:7:5:7:6 | call to f1 | query-tests/Documentation/DocumentApi/user2.c |
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user1.c:14:5:14:6 | call to f6 | query-tests/Documentation/DocumentApi/user1.c |
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user2.c:10:5:10:6 | call to f6 | query-tests/Documentation/DocumentApi/user2.c |
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:9:5:9:10 | call to proto6 | comment_prototypes_caller1.c |
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:9:5:9:10 | call to proto6 | comment_prototypes_caller2.c |
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:10:5:10:10 | call to proto7 | comment_prototypes_caller1.c |
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:10:5:10:10 | call to proto7 | comment_prototypes_caller2.c |
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:12:5:12:10 | call to proto9 | comment_prototypes_caller1.c |
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:12:5:12:10 | call to proto9 | comment_prototypes_caller2.c |
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:13:5:13:11 | call to proto10 | comment_prototypes_caller1.c |
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:13:5:13:11 | call to proto10 | comment_prototypes_caller2.c |
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:14:5:14:11 | call to proto11 | comment_prototypes_caller1.c |
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:14:5:14:11 | call to proto11 | comment_prototypes_caller2.c |
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:16:5:16:11 | call to proto13 | comment_prototypes_caller1.c |
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:16:5:16:11 | call to proto13 | comment_prototypes_caller2.c |
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user1.c:9:5:9:6 | call to f1 | user1.c |
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user2.c:7:5:7:6 | call to f1 | user2.c |
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user1.c:14:5:14:6 | call to f6 | user1.c |
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user2.c:10:5:10:6 | call to f6 | user2.c |

View File

@@ -10,3 +10,4 @@
| test.c:15:2:15:7 | call to printf | Format for printf expects 3 arguments but given 2 |
| test.c:19:2:19:7 | call to printf | Format for printf expects 2 arguments but given 1 |
| test.c:29:3:29:8 | call to printf | Format for printf expects 2 arguments but given 1 |
| test.c:53:2:53:10 | call to my_logger | Format for my_logger expects 3 arguments but given 2 |

View File

@@ -44,3 +44,6 @@ void test_custom_printf2()
printf("", "%i %i", 100, 200); // GOOD
printf("%i %i", "" ); // GOOD
}
extern "C" void my_logger(int param, char *fmt, ...) __attribute__((format(printf, 2, 3))) {}

View File

@@ -46,4 +46,12 @@ void test(int i, const char *str)
printf("%Y", 1, 2); // GOOD (unknown format character, this might be correct)
printf("%1.1Y", 1, 2); // GOOD (unknown format character, this might be correct)
printf("%*.*Y", 1, 2); // GOOD (unknown format character, this might be correct)
// Implicit logger function declaration
my_logger(0, "%i %i %i %i %i %i\n", 1, 2, 3, 4, 5, 6); // GOOD
my_logger(0, "%i %i %i\n", 1, 2, 3); // GOOD
my_logger(0, "%i %i %i\n", 1, 2); // BAD (too few format arguments)
}
// A spurious definition of my_logger
extern void my_logger(int param, char *fmt, int, int, int, int, int);

View File

@@ -1,4 +1,4 @@
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibC<\|>unknown | 5 |
| /query-tests/Metrics/Dependencies/include.h<\|>LibD<\|>unknown | 1 |
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibA<\|>unknown | 1 |
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibB<\|>unknown | 1 |
| /main.cpp<\|>LibC<\|>unknown | 5 |
| /include.h<\|>LibD<\|>unknown | 1 |
| /main.cpp<\|>LibA<\|>unknown | 1 |
| /main.cpp<\|>LibB<\|>unknown | 1 |

View File

@@ -1,4 +1,4 @@
| /query-tests/Metrics/Dependencies/include.h<\|>LibD<\|>unknown | include.h:0:0:0:0 | include.h |
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibA<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibB<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibC<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
| /include.h<\|>LibD<\|>unknown | include.h:0:0:0:0 | include.h |
| /main.cpp<\|>LibA<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
| /main.cpp<\|>LibB<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
| /main.cpp<\|>LibC<\|>unknown | main.cpp:0:0:0:0 | main.cpp |

View File

@@ -1,5 +1,6 @@
edges
nodes
| errors.cpp:13:7:13:7 | definition of x | semmle.label | definition of x |
| test.cpp:11:6:11:8 | definition of foo | semmle.label | definition of foo |
| test.cpp:111:6:111:8 | definition of foo | semmle.label | definition of foo |
| test.cpp:226:7:226:7 | definition of x | semmle.label | definition of x |
@@ -14,6 +15,7 @@ nodes
| test.cpp:472:6:472:6 | definition of x | semmle.label | definition of x |
| test.cpp:479:6:479:6 | definition of x | semmle.label | definition of x |
#select
| errors.cpp:14:18:14:18 | x | errors.cpp:13:7:13:7 | definition of x | errors.cpp:13:7:13:7 | definition of x | The variable $@ may not be initialized at this access. | errors.cpp:13:7:13:7 | x | x |
| test.cpp:12:6:12:8 | foo | test.cpp:11:6:11:8 | definition of foo | test.cpp:11:6:11:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
| test.cpp:113:6:113:8 | foo | test.cpp:111:6:111:8 | definition of foo | test.cpp:111:6:111:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
| test.cpp:227:3:227:3 | x | test.cpp:226:7:226:7 | definition of x | test.cpp:226:7:226:7 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:226:7:226:7 | x | x |

View File

@@ -0,0 +1,15 @@
// semmle-extractor-options: --expect_errors
int f1() {
int x;
initialize(&x); // error expression - initialize() is not defined
return x; // GOOD - assume x is initialized
}
void * operator new(unsigned long, bool);
void operator delete(void*, bool);
int f2() {
int x;
new(true) int (x); // BAD, ignore implicit error expression
}

View File

@@ -53,4 +53,59 @@ void NonStringFalsePositiveTest2(unsigned char* buffer)
{
wchar_t *lpWchar = NULL;
lpWchar = (LPWSTR)buffer; // Possible False Positive
}
}
typedef unsigned char BYTE;
using FOO = BYTE*;
void NonStringFalsePositiveTest3(FOO buffer)
{
wchar_t *lpWchar = NULL;
lpWchar = (LPWSTR)buffer; // GOOD
}
#define UNICODE 0x8
// assume EMPTY_MACRO is tied to if UNICODE is enabled
#ifdef EMPTY_MACRO
typedef WCHAR* LPTSTR;
#else
typedef char* LPTSTR;
#endif
void CheckedConversionFalsePositiveTest3(unsigned short flags, LPTSTR buffer)
{
wchar_t *lpWchar = NULL;
if(flags & UNICODE)
lpWchar = (LPWSTR)buffer; // GOOD
else
lpWchar = (LPWSTR)buffer; // BUG
if((flags & UNICODE) == 0x8)
lpWchar = (LPWSTR)buffer; // GOOD
else
lpWchar = (LPWSTR)buffer; // BUG
if((flags & UNICODE) != 0x8)
lpWchar = (LPWSTR)buffer; // BUG
else
lpWchar = (LPWSTR)buffer; // GOOD
// Bad operator precedence
if(flags & UNICODE == 0x8)
lpWchar = (LPWSTR)buffer; // BUG
else
lpWchar = (LPWSTR)buffer; // BUG
if((flags & UNICODE) != 0)
lpWchar = (LPWSTR)buffer; // GOOD
else
lpWchar = (LPWSTR)buffer; // BUG
if((flags & UNICODE) == 0)
lpWchar = (LPWSTR)buffer; // BUG
else
lpWchar = (LPWSTR)buffer; // GOOD
lpWchar = (LPWSTR)buffer; // BUG
}

View File

@@ -3,3 +3,11 @@
| WcharCharConversion.cpp:24:22:24:27 | lpChar | Conversion from char * to wchar_t *. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:26:23:26:28 | lpChar | Conversion from char * to LPCWSTR. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:27:17:27:22 | lpChar | Conversion from char * to LPWSTR. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:82:21:82:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:87:21:87:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:90:21:90:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:96:21:96:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:98:21:98:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:103:21:103:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:106:21:106:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
| WcharCharConversion.cpp:110:20:110:25 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |

View File

@@ -64,7 +64,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
catch (Exception exc)
{
Context.ExtractionError($"Couldn't read file: {originalPath}. {exc.Message}", null, null, exc.StackTrace);
Context.ExtractionError($"Couldn't read file: {originalPath}. {exc.Message}", null, null, exc.StackTrace, Semmle.Util.Logging.Severity.Warning);
}
}

View File

@@ -1,3 +1,7 @@
## 1.7.26
No user-facing changes.
## 1.7.25
No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.25
lastReleaseVersion: 1.7.26

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.7.26-dev
version: 1.7.27-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,7 @@
## 1.7.26
No user-facing changes.
## 1.7.25
No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.25
lastReleaseVersion: 1.7.26

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.7.26-dev
version: 1.7.27-dev
groups:
- csharp
- solorigate

View File

@@ -61,8 +61,3 @@ query predicate preBasicBlockConsistency(ControlFlowElement cfe1, ControlFlowEle
bbIntraSuccInconsistency(cfe1, cfe2) and
s = "intra succ inconsistency"
}
query predicate multipleToString(Node n, string s) {
s = strictconcat(n.toString(), ",") and
strictcount(n.toString()) > 1
}

View File

@@ -1,3 +1,19 @@
## 3.0.0
### Breaking Changes
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using `Attribute.Getter` or `Attribute.Setter` in the model `ext` field applies the model to the getter or setter for properties and indexers. Prior to this change `Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the `Attribute` feature directly on a property for a property setter needs to be changed to `Attribute.Setter`.
* C#: Remove all CIL tables and related QL library functionality.
### Deprecated APIs
* The class `ThreatModelFlowSource` has been renamed to `ActiveThreatModelSource` to more clearly reflect it only contains the currently active threat model sources. `ThreatModelFlowSource` has been marked as deprecated.
### Minor Analysis Improvements
* `DataFlow::Node` instances are no longer created for library methods and fields that are not callable (either statically or dynamically) or otherwise referred to from source code. This may affect third-party queries that use these nodes to identify library methods or fields that are present in DLL files where those methods or fields are unreferenced. If this presents a problem, consider using `Callable` and other non-dataflow classes to identify such library entities.
* C#: Add extractor support for attributes on indexers.
## 2.0.0
### Breaking Changes

View File

@@ -1,4 +0,0 @@
---
category: breaking
---
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using `Attribute.Getter` or `Attribute.Setter` in the model `ext` field applies the model to the getter or setter for properties and indexers. Prior to this change `Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the `Attribute` feature directly on a property for a property setter needs to be changed to `Attribute.Setter`.

View File

@@ -1,4 +0,0 @@
---
category: breaking
---
* C#: Remove all CIL tables and related QL library functionality.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* C#: Add extractor support for attributes on indexers.

View File

@@ -0,0 +1,15 @@
## 3.0.0
### Breaking Changes
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using `Attribute.Getter` or `Attribute.Setter` in the model `ext` field applies the model to the getter or setter for properties and indexers. Prior to this change `Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the `Attribute` feature directly on a property for a property setter needs to be changed to `Attribute.Setter`.
* C#: Remove all CIL tables and related QL library functionality.
### Deprecated APIs
* The class `ThreatModelFlowSource` has been renamed to `ActiveThreatModelSource` to more clearly reflect it only contains the currently active threat model sources. `ThreatModelFlowSource` has been marked as deprecated.
### Minor Analysis Improvements
* `DataFlow::Node` instances are no longer created for library methods and fields that are not callable (either statically or dynamically) or otherwise referred to from source code. This may affect third-party queries that use these nodes to identify library methods or fields that are present in DLL files where those methods or fields are unreferenced. If this presents a problem, consider using `Callable` and other non-dataflow classes to identify such library entities.
* C#: Add extractor support for attributes on indexers.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 2.0.0
lastReleaseVersion: 3.0.0

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all
version: 2.0.1-dev
version: 3.0.1-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp

View File

@@ -15,11 +15,19 @@ class CfgScope extends Element, @top_level_exprorstmt_parent {
CfgScope() {
this.getFile().fromSource() and
(
this instanceof Callable
this =
any(Callable c |
c.(Constructor).hasInitializer()
or
InitializerSplitting::constructorInitializes(c, _)
or
c.hasBody()
)
or
// For now, static initializer values have their own scope. Eventually, they
// should be treated like instance initializers.
this.(Assignable).(Modifiable).isStatic()
this.(Assignable).(Modifiable).isStatic() and
expr_parent_top_level_adjusted2(_, _, this)
)
}
}

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -995,6 +995,52 @@ private class InstanceCallable extends Callable {
Location getARelevantLocation() { result = l }
}
/**
* A callable which is either itself defined in source or which is the target
* of some call in source, and therefore ought to have dataflow nodes created.
*
* Note that for library methods these are always unbound declarations, since
* generic instantiations never have dataflow nodes constructed.
*/
private class CallableUsedInSource extends Callable {
CallableUsedInSource() {
// Should generate nodes even for abstract methods declared in source
this.fromSource()
or
// Should generate nodes even for synthetic methods derived from source
this.hasBody()
or
exists(Callable target |
exists(Call c |
// Note that getADynamicTarget does not always include getTarget.
target = c.getTarget()
or
// Note that getARuntimeTarget cannot be used here, because the
// DelegateLikeCall case depends on lambda-flow, which in turn
// uses the dataflow library; hence this would introduce recursion
// into the definition of data-flow nodes.
exists(DispatchCall dc | c = dc.getCall() | target = dc.getADynamicTarget())
)
or
target = any(CallableAccess ca).getTarget()
|
this = target.getUnboundDeclaration()
)
}
}
/**
* A field or property which is either itself defined in source or which is the target
* of some access in source, and therefore ought to have dataflow nodes created.
*/
private class FieldOrPropertyUsedInSource extends FieldOrProperty {
FieldOrPropertyUsedInSource() {
this.fromSource()
or
this.getAnAccess().fromSource()
}
}
/** A collection of cached types and predicates to be evaluated in the same stage. */
cached
private module Cached {
@@ -1018,8 +1064,13 @@ private module Cached {
TAssignableDefinitionNode(AssignableDefinition def, ControlFlow::Node cfn) {
cfn = def.getExpr().getAControlFlowNode()
} or
TExplicitParameterNode(Parameter p, DataFlowCallable c) { p = c.asCallable(_).getAParameter() } or
TInstanceParameterNode(InstanceCallable c, Location l) { l = c.getARelevantLocation() } or
TExplicitParameterNode(Parameter p, DataFlowCallable c) {
p = c.asCallable(_).(CallableUsedInSource).getAParameter()
} or
TInstanceParameterNode(InstanceCallable c, Location l) {
c instanceof CallableUsedInSource and
l = c.getARelevantLocation()
} or
TDelegateSelfReferenceNode(Callable c) { lambdaCreationExpr(_, c) } or
TLocalFunctionCreationNode(ControlFlow::Nodes::ElementNode cfn, Boolean isPostUpdate) {
cfn.getAstNode() instanceof LocalFunctionStmt
@@ -1055,11 +1106,13 @@ private module Cached {
or
lambdaCallExpr(_, cfn)
} or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) {
sn.getSummarizedCallable() instanceof CallableUsedInSource
} or
TParamsArgumentNode(ControlFlow::Node callCfn) {
callCfn = any(Call c | isParamsArg(c, _, _)).getAControlFlowNode()
} or
TFlowInsensitiveFieldNode(FieldOrProperty f) { f.isFieldLike() } or
TFlowInsensitiveFieldNode(FieldOrPropertyUsedInSource f) { f.isFieldLike() } or
TFlowInsensitiveCapturedVariableNode(LocalScopeVariable v) { v.isCaptured() } or
TInstanceParameterAccessNode(ControlFlow::Node cfn, Boolean isPostUpdate) {
cfn = getAPrimaryConstructorParameterCfn(_)

View File

@@ -299,9 +299,12 @@ class ContentSet extends TContentSet {
*/
predicate isProperty(Property p) { this = TPropertyContentSet(p) }
/** Holds if this content set represent the field `f`. */
/** Holds if this content set represents the field `f`. */
predicate isField(Field f) { this.isSingleton(TFieldContent(f)) }
/** Holds if this content set represents the synthetic field `s`. */
predicate isSyntheticField(string s) { this.isSingleton(TSyntheticFieldContent(s)) }
/** Holds if this content set represents an element in a collection. */
predicate isElement() { this.isSingleton(TElementContent()) }

View File

@@ -318,7 +318,7 @@ private predicate elementSpec(
or
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _)
or
neutralModel(namespace, type, name, signature, _, _) and ext = "" and subtypes = false
neutralModel(namespace, type, name, signature, _, _) and ext = "" and subtypes = true
}
private predicate elementSpec(
@@ -602,7 +602,7 @@ private predicate interpretSummary(
predicate interpretNeutral(UnboundCallable c, string kind, string provenance) {
exists(string namespace, string type, string name, string signature |
neutralModel(namespace, type, name, signature, kind, provenance) and
c = interpretElement(namespace, type, false, name, signature, "")
c = interpretElement(namespace, type, true, name, signature, "")
)
}

View File

@@ -18,7 +18,7 @@ private predicate needsChecks(ActionMethod m) { m.isEdit() and not m.isAdmin() }
* that may indicate that it's used as the ID for some resource
*/
private predicate hasIdParameter(ActionMethod m) {
exists(ThreatModelFlowSource src | src.getEnclosingCallable() = m |
exists(ActiveThreatModelSource src | src.getEnclosingCallable() = m |
src.asParameter().getName().toLowerCase().matches(["%id", "%idx"])
or
// handle cases like `Request.QueryString["Id"]`

View File

@@ -55,7 +55,7 @@ deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource
deprecated class LocalSource extends DataFlow::Node instanceof LocalFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }

View File

@@ -57,7 +57,7 @@ module CommandInjection = TaintTracking::Global<CommandInjectionConfig>;
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/** Command Injection sinks defined through Models as Data. */
private class ExternalCommandInjectionExprSink extends Sink {

View File

@@ -54,7 +54,7 @@ module ConditionalBypass = TaintTracking::Global<ConditionalBypassConfig>;
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/** The result of a reverse dns may be user-controlled. */
class ReverseDnsSource extends Source {

View File

@@ -73,14 +73,14 @@ class ExternalApiDataNode extends DataFlow::Node {
}
}
/** A configuration for tracking flow from `ThreatModelFlowSource`s to `ExternalApiDataNode`s. */
/** A configuration for tracking flow from `ActiveThreatModelSource`s to `ExternalApiDataNode`s. */
private module RemoteSourceToExternalApiConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
}
/** A module for tracking flow from `ThreatModelFlowSource`s to `ExternalApiDataNode`s. */
/** A module for tracking flow from `ActiveThreatModelSource`s to `ExternalApiDataNode`s. */
module RemoteSourceToExternalApi = TaintTracking::Global<RemoteSourceToExternalApiConfig>;
/** A node representing untrusted data being passed to an external API. */

View File

@@ -60,7 +60,7 @@ module LdapInjection = TaintTracking::Global<LdapInjectionConfig>;
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/** LDAP sinks defined through Models as Data. */
private class ExternalLdapExprSink extends Sink {

View File

@@ -42,8 +42,8 @@ private module LogForgingConfig implements DataFlow::ConfigSig {
*/
module LogForging = TaintTracking::Global<LogForgingConfig>;
/** A source of remote user input. */
private class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
/** A source supported by the current threat model. */
private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
private class HtmlSanitizer extends Sanitizer {
HtmlSanitizer() { this.asExpr() instanceof HtmlSanitizedExpr }

View File

@@ -48,7 +48,7 @@ private module MissingXmlValidationConfig implements DataFlow::ConfigSig {
module MissingXmlValidation = TaintTracking::Global<MissingXmlValidationConfig>;
/**
* DEPRECATED: Use `ThreatModelFlowSource` instead.
* DEPRECATED: Use `ActiveThreatModelSource` instead.
*
* A source of remote user input.
*/
@@ -57,7 +57,7 @@ deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource
/**
* A source supported by the current threat model.
*/
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/**
* The input argument to a call to `XmlReader.Create` where the input will not be validated against

View File

@@ -49,7 +49,7 @@ module ReDoS = TaintTracking::Global<ReDoSConfig>;
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/**
* An expression that represents a regular expression with potential exponential behavior.

View File

@@ -48,7 +48,7 @@ module RegexInjection = TaintTracking::Global<RegexInjectionConfig>;
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/**
* A `pattern` argument to a construction of a `Regex`.

View File

@@ -54,7 +54,7 @@ deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource
deprecated class LocalSource extends DataFlow::Node instanceof LocalFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/** An argument to the `ConnectionString` property on a data connection class. */
class SqlConnectionStringSink extends Sink {

View File

@@ -65,7 +65,7 @@ deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource
deprecated class LocalSource extends DataFlow::Node instanceof LocalFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/** An SQL expression passed to an API call that executes SQL. */
class SqlInjectionExprSink extends Sink {

View File

@@ -50,7 +50,7 @@ module TaintedPath = TaintTracking::Global<TaintedPathConfig>;
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/**
* A path argument to a `File` method call.

View File

@@ -49,7 +49,7 @@ abstract private class ConstructorOrStaticMethodSink extends Sink { }
*/
abstract class Sanitizer extends DataFlow::Node { }
private class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/**
* User input to object method call deserialization flow tracking configuration.

View File

@@ -52,7 +52,7 @@ module UrlRedirect = TaintTracking::Global<UrlRedirectConfig>;
deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { }
/** A source supported by the current threat model. */
class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/** URL Redirection sinks defined through Models as Data. */
private class ExternalUrlRedirectExprSink extends Sink {

View File

@@ -15,7 +15,7 @@ private import semmle.code.csharp.security.Sanitizers
*/
abstract class Source extends DataFlow::Node { }
private class ThreatModelSource extends Source instanceof ThreatModelFlowSource { }
private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
/**
* A data flow sink for untrusted user input used in XML processing.

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