mirror of
https://github.com/github/codeql.git
synced 2026-04-22 15:25:18 +02:00
Merge branch 'main' into pin
This commit is contained in:
3
.github/workflows/go-tests-other-os.yml
vendored
3
.github/workflows/go-tests-other-os.yml
vendored
@@ -26,9 +26,8 @@ jobs:
|
||||
uses: ./go/actions/test
|
||||
|
||||
test-win:
|
||||
if: github.repository_owner == 'github'
|
||||
name: Test Windows
|
||||
runs-on: windows-latest-xl
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -62,6 +62,7 @@ node_modules/
|
||||
|
||||
# Temporary folders for working with generated models
|
||||
.model-temp
|
||||
/mad-generation-build
|
||||
|
||||
# bazel-built in-tree extractor packs
|
||||
/*/extractor-pack
|
||||
|
||||
@@ -10,6 +10,7 @@ members = [
|
||||
"rust/ast-generator",
|
||||
"rust/autobuild",
|
||||
]
|
||||
exclude = ["mad-generation-build"]
|
||||
|
||||
[patch.crates-io]
|
||||
# patch for build script bug preventing bazel build
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed a problem where `asExpr()` on `DataFlow::Node` would never return `ArrayAggregateLiteral`s.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* Deleted the deprecated `userInputArgument` predicate and its convenience accessor from the `Security.qll`.
|
||||
* Deleted the deprecated `userInputReturned` predicate and its convenience accessor from the `Security.qll`.
|
||||
* Deleted the deprecated `userInputReturn` predicate from the `Security.qll`.
|
||||
* Deleted the deprecated `isUserInput` predicate and its convenience accessor from the `Security.qll`.
|
||||
* Deleted the deprecated `userInputArgument` predicate from the `SecurityOptions.qll`.
|
||||
* Deleted the deprecated `userInputReturned` predicate from the `SecurityOptions.qll`.
|
||||
@@ -1,7 +1,8 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.Language
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
/**
|
||||
* Traces 'known algorithms' to AVCs, specifically
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import OpenSSLAlgorithmInstanceBase
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
import AlgToAVCFlow
|
||||
private import experimental.quantum.Language
|
||||
private import OpenSSLAlgorithmInstanceBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import AlgToAVCFlow
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSSLBlockModeAlgorithmConstant`, converts this to a block family type.
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import KnownAlgorithmConstants
|
||||
import Crypto::KeyOpAlg as KeyOpAlg
|
||||
import OpenSSLAlgorithmInstanceBase
|
||||
import PaddingAlgorithmInstance
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import AlgToAVCFlow
|
||||
import BlockAlgorithmInstance
|
||||
private import experimental.quantum.Language
|
||||
private import KnownAlgorithmConstants
|
||||
private import Crypto::KeyOpAlg as KeyOpAlg
|
||||
private import OpenSSLAlgorithmInstanceBase
|
||||
private import PaddingAlgorithmInstance
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import AlgToAVCFlow
|
||||
private import BlockAlgorithmInstance
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSSLCipherAlgorithmConstant`, converts this to a cipher family type.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import cpp
|
||||
private import experimental.quantum.Language
|
||||
private import KnownAlgorithmConstants
|
||||
private import OpenSSLAlgorithmInstanceBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import AlgToAVCFlow
|
||||
|
||||
class KnownOpenSSLEllipticCurveConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::EllipticCurveInstance instanceof KnownOpenSSLEllipticCurveAlgorithmConstant
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
|
||||
KnownOpenSSLEllipticCurveConstantAlgorithmInstance() {
|
||||
// Two possibilities:
|
||||
// 1) The source is a literal and flows to a getter, then we know we have an instance
|
||||
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectAlgorithmValueConsumer and getterCall = this
|
||||
}
|
||||
|
||||
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }
|
||||
|
||||
override string getRawEllipticCurveName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
override Crypto::TEllipticCurveType getEllipticCurveType() {
|
||||
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.(KnownOpenSSLEllipticCurveAlgorithmConstant)
|
||||
.getNormalizedName(), _, result)
|
||||
}
|
||||
|
||||
override int getKeySize() {
|
||||
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.(KnownOpenSSLEllipticCurveAlgorithmConstant)
|
||||
.getNormalizedName(), result, _)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import AlgToAVCFlow
|
||||
private import experimental.quantum.Language
|
||||
private import KnownAlgorithmConstants
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
private import AlgToAVCFlow
|
||||
|
||||
predicate knownOpenSSLConstantToHashFamilyType(
|
||||
KnownOpenSSLHashAlgorithmConstant e, Crypto::THashType type
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
import experimental.quantum.OpenSSL.LibraryDetector
|
||||
private import experimental.quantum.OpenSSL.LibraryDetector
|
||||
|
||||
predicate resolveAlgorithmFromExpr(Expr e, string normalizedName, string algType) {
|
||||
resolveAlgorithmFromCall(e, normalizedName, algType)
|
||||
@@ -67,6 +67,15 @@ class KnownOpenSSLHashAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
|
||||
}
|
||||
}
|
||||
|
||||
class KnownOpenSSLEllipticCurveAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
|
||||
KnownOpenSSLEllipticCurveAlgorithmConstant() {
|
||||
exists(string algType |
|
||||
resolveAlgorithmFromExpr(this, _, algType) and
|
||||
algType.toLowerCase().matches("elliptic_curve")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a call to a 'direct algorithm getter', e.g., EVP_MD5()
|
||||
* This approach to fetching algorithms was used in OpenSSL 1.0.2.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
abstract class OpenSSLAlgorithmInstance extends Crypto::AlgorithmInstance {
|
||||
abstract OpenSSLAlgorithmValueConsumer getAVC();
|
||||
|
||||
@@ -3,3 +3,4 @@ import CipherAlgorithmInstance
|
||||
import PaddingAlgorithmInstance
|
||||
import BlockAlgorithmInstance
|
||||
import HashAlgorithmInstance
|
||||
import EllipticCurveAlgorithmInstance
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import OpenSSLAlgorithmInstanceBase
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import AlgToAVCFlow
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import experimental.quantum.Language
|
||||
private import OpenSSLAlgorithmInstanceBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
private import AlgToAVCFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSSLPaddingAlgorithmConstant`, converts this to a padding family type.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.LibraryDetector
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
import OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.LibraryDetector
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
private import OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
abstract class CipherAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { }
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
// TODO: can self referential to itself, which is also an algorithm (Known algorithm)
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import cpp
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.LibraryDetector
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
|
||||
abstract class EllipticCurveValueConsumer extends OpenSSLAlgorithmValueConsumer { }
|
||||
|
||||
//https://docs.openssl.org/3.0/man3/EC_KEY_new/#name
|
||||
class EVPEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer {
|
||||
DataFlow::Node valueArgNode;
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EVPEllipticCurveAlgorithmConsumer() {
|
||||
resultNode.asExpr() = this.(Call) and // in all cases the result is the return
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget()) and
|
||||
(
|
||||
this.(Call).getTarget().getName() in ["EVP_EC_gen", "EC_KEY_new_by_curve_name"] and
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EC_KEY_new_by_curve_name_ex", "EVP_PKEY_CTX_set_ec_paramgen_curve_nid"
|
||||
] and
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(2)
|
||||
)
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
|
||||
}
|
||||
|
||||
override DataFlow::Node getResultNode() { result = resultNode }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
// import EVPHashInitializer
|
||||
// import EVPHashOperation
|
||||
// import EVPHashAlgorithmSource
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
import experimental.quantum.OpenSSL.LibraryDetector
|
||||
private import experimental.quantum.Language
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
private import experimental.quantum.OpenSSL.LibraryDetector
|
||||
|
||||
abstract class HashAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { }
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import experimental.quantum.Language
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import experimental.quantum.Language
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
abstract class OpenSSLAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer instanceof Call {
|
||||
/**
|
||||
|
||||
@@ -3,3 +3,4 @@ import CipherAlgorithmValueConsumer
|
||||
import DirectAlgorithmValueConsumer
|
||||
import PaddingAlgorithmValueConsumer
|
||||
import HashAlgorithmValueConsumer
|
||||
import EllipticCurveAlgorithmValueConsumer
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import cpp
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.LibraryDetector
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
import OpenSSLAlgorithmValueConsumerBase
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.LibraryDetector
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
private import OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
abstract class PaddingAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { }
|
||||
|
||||
|
||||
@@ -6,4 +6,5 @@ module OpenSSLModel {
|
||||
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
||||
import experimental.quantum.OpenSSL.Random
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Models cipher initialization for EVP cipher operations.
|
||||
*/
|
||||
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
|
||||
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
import EVPCipherInitializer
|
||||
import OpenSSLOperationBase
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
private import EVPCipherInitializer
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
@@ -74,8 +74,8 @@ class EVP_Cipher_Call extends EVP_Cipher_Operation {
|
||||
}
|
||||
|
||||
// NOTE: not modeled as cipher operations, these are intermediate calls
|
||||
class EVP_Update_Call extends Call {
|
||||
EVP_Update_Call() {
|
||||
class EVP_Cipher_Update_Call extends Call {
|
||||
EVP_Cipher_Update_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
|
||||
]
|
||||
@@ -88,15 +88,15 @@ class EVP_Update_Call extends Call {
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EVP_Final_Call extends EVP_Cipher_Operation {
|
||||
EVP_Final_Call() {
|
||||
class EVP_Cipher_Final_Call extends EVP_Cipher_Operation {
|
||||
EVP_Cipher_Final_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptFinal_ex", "EVP_DecryptFinal_ex", "EVP_CipherFinal_ex", "EVP_EncryptFinal",
|
||||
"EVP_DecryptFinal", "EVP_CipherFinal"
|
||||
]
|
||||
}
|
||||
|
||||
EVP_Update_Call getUpdateCalls() {
|
||||
EVP_Cipher_Update_Call getUpdateCalls() {
|
||||
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
*/
|
||||
|
||||
import experimental.quantum.Language
|
||||
import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
import experimental.quantum.OpenSSL.LibraryDetector
|
||||
import OpenSSLOperationBase
|
||||
import EVPHashInitializer
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
private import experimental.quantum.OpenSSL.LibraryDetector
|
||||
private import OpenSSLOperationBase
|
||||
private import EVPHashInitializer
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
// import EVPHashConsumers
|
||||
abstract class EVP_Hash_Operation extends OpenSSLOperation, Crypto::HashOperationInstance {
|
||||
@@ -16,6 +16,16 @@ abstract class EVP_Hash_Operation extends OpenSSLOperation, Crypto::HashOperatio
|
||||
EVP_Hash_Initializer getInitCall() {
|
||||
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, the algorithm value comes from the init call.
|
||||
* There are variants where this isn't true, in which case the
|
||||
* subclass should override this method.
|
||||
*/
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
DataFlow::exprNode(this.getInitCall().getAlgorithmArg()))
|
||||
}
|
||||
}
|
||||
|
||||
private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
|
||||
@@ -88,30 +98,34 @@ class EVP_Digest_Operation extends EVP_Hash_Operation {
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
|
||||
}
|
||||
// // override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
// // AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
// // DataFlow::exprNode(this.getInitCall().getAlgorithmArg()))
|
||||
// // }
|
||||
// // ***** TODO *** complete modelinlg for hash operations, but have consideration for terminal and non-terminal (non intermedaite) steps
|
||||
// // see the JCA. May need to update the cipher operations similarly
|
||||
// // ALSO SEE cipher for how we currently model initialization of the algorithm through an init call
|
||||
// class EVP_DigestUpdate_Operation extends EVP_Hash_Operation {
|
||||
// EVP_DigestUpdate_Operation() {
|
||||
// this.(Call).getTarget().getName() = "EVP_DigestUpdate" and
|
||||
// isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
// }
|
||||
// override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
|
||||
// this.getInitCall().getAlgorithmArg() = result
|
||||
// }
|
||||
// }
|
||||
// class EVP_DigestFinal_Variants_Operation extends EVP_Hash_Operation {
|
||||
// EVP_DigestFinal_Variants_Operation() {
|
||||
// this.(Call).getTarget().getName() in [
|
||||
// "EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
|
||||
// ] and
|
||||
// isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
// }
|
||||
// override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
|
||||
// this.getInitCall().getAlgorithmArg() = result
|
||||
// }
|
||||
// }
|
||||
|
||||
// NOTE: not modeled as hash operations, these are intermediate calls
|
||||
class EVP_Digest_Update_Call extends Call {
|
||||
EVP_Digest_Update_Call() { this.(Call).getTarget().getName() in ["EVP_DigestUpdate"] }
|
||||
|
||||
Expr getInputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
DataFlow::Node getInputNode() { result.asExpr() = this.getInputArg() }
|
||||
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EVP_Digest_Final_Call extends EVP_Hash_Operation {
|
||||
EVP_Digest_Final_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
|
||||
]
|
||||
}
|
||||
|
||||
EVP_Digest_Update_Call getUpdateCalls() {
|
||||
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
|
||||
}
|
||||
|
||||
override Expr getInputArg() { result = this.getUpdateCalls().getInputArg() }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
|
||||
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result = this.getOutputNode() }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import experimental.quantum.Language
|
||||
private import experimental.quantum.Language
|
||||
|
||||
abstract class OpenSSLOperation extends Crypto::OperationInstance instanceof Call {
|
||||
abstract Expr getInputArg();
|
||||
|
||||
@@ -98,19 +98,6 @@ class Node extends TNode {
|
||||
/** Gets the location of this element. */
|
||||
Location getLocation() { none() } // overridden by subclasses
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
deprecated predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an upper bound on the type of this node.
|
||||
*/
|
||||
|
||||
@@ -538,19 +538,6 @@ class Node extends TIRDataFlowNode {
|
||||
none() // overridden by subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
deprecated predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
cached
|
||||
final string toString() {
|
||||
|
||||
@@ -45,6 +45,28 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getRankedElementExpr(ArrayAggregateLiteral aggr, int rnk) {
|
||||
result =
|
||||
rank[rnk + 1](Expr e, int elementIndex, int position |
|
||||
e = aggr.getElementExpr(elementIndex, position)
|
||||
|
|
||||
e order by elementIndex, position
|
||||
)
|
||||
}
|
||||
|
||||
private class LastArrayAggregateStore extends StoreInstruction {
|
||||
ArrayAggregateLiteral aggr;
|
||||
|
||||
LastArrayAggregateStore() {
|
||||
exists(int rnk |
|
||||
this.getSourceValue().getUnconvertedResultExpression() = getRankedElementExpr(aggr, rnk) and
|
||||
not exists(getRankedElementExpr(aggr, rnk + 1))
|
||||
)
|
||||
}
|
||||
|
||||
ArrayAggregateLiteral getArrayAggregateLiteral() { result = aggr }
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
|
||||
// IR construction inserts an additional cast to a `size_t` on the extent
|
||||
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
|
||||
@@ -95,6 +117,16 @@ private module Cached {
|
||||
tco.producesExprResult() and
|
||||
result = asDefinitionImpl0(instr)
|
||||
)
|
||||
or
|
||||
// IR construction breaks an array aggregate literal `{1, 2, 3}` into a
|
||||
// sequence of `StoreInstruction`s. So there's no instruction `i` for which
|
||||
// `i.getUnconvertedResultExpression() instanceof ArrayAggregateLiteral`.
|
||||
// So we map the instruction node corresponding to the last `Store`
|
||||
// instruction of the sequence to the result of the array aggregate
|
||||
// literal. This makes sense since this store will immediately flow into
|
||||
// the indirect node representing the array. So this node does represent
|
||||
// the array after it has been fully initialized.
|
||||
result = instr.(LastArrayAggregateStore).getArrayAggregateLiteral()
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl(Instruction instr) {
|
||||
|
||||
@@ -10,7 +10,7 @@ private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||
*/
|
||||
class SemBasicBlock extends Specific::BasicBlock {
|
||||
/** Holds if this block (transitively) dominates `otherblock`. */
|
||||
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
|
||||
final predicate dominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
|
||||
|
||||
/** Gets an expression that is evaluated in this basic block. */
|
||||
final SemExpr getAnExpr() { result.getBasicBlock() = this }
|
||||
|
||||
@@ -42,58 +42,6 @@ class SecurityOptions extends string {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The argument of the given function is filled in from user input.
|
||||
*/
|
||||
deprecated predicate userInputArgument(FunctionCall functionCall, int arg) {
|
||||
exists(string fname |
|
||||
functionCall.getTarget().hasGlobalOrStdName(fname) and
|
||||
exists(functionCall.getArgument(arg)) and
|
||||
(
|
||||
fname = ["fread", "fgets", "fgetws", "gets"] and arg = 0
|
||||
or
|
||||
fname = "scanf" and arg >= 1
|
||||
or
|
||||
fname = "fscanf" and arg >= 2
|
||||
)
|
||||
or
|
||||
functionCall.getTarget().hasGlobalName(fname) and
|
||||
exists(functionCall.getArgument(arg)) and
|
||||
fname = "getaddrinfo" and
|
||||
arg = 3
|
||||
)
|
||||
or
|
||||
exists(RemoteFlowSourceFunction remote, FunctionOutput output |
|
||||
functionCall.getTarget() = remote and
|
||||
output.isParameterDerefOrQualifierObject(arg) and
|
||||
remote.hasRemoteFlowSource(output, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value of the given function is filled in from user input.
|
||||
*/
|
||||
deprecated predicate userInputReturned(FunctionCall functionCall) {
|
||||
exists(string fname |
|
||||
functionCall.getTarget().getName() = fname and
|
||||
(
|
||||
fname = ["fgets", "gets"] or
|
||||
this.userInputReturn(fname)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(RemoteFlowSourceFunction remote, FunctionOutput output |
|
||||
functionCall.getTarget() = remote and
|
||||
(output.isReturnValue() or output.isReturnValueDeref()) and
|
||||
remote.hasRemoteFlowSource(output, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Users should override `userInputReturned()` instead.
|
||||
*/
|
||||
deprecated predicate userInputReturn(string function) { none() }
|
||||
|
||||
/**
|
||||
* The argument of the given function is used for running a process or loading
|
||||
* a library.
|
||||
@@ -108,29 +56,6 @@ class SecurityOptions extends string {
|
||||
function = ["LoadLibrary", "LoadLibraryA", "LoadLibraryW"] and arg = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* This predicate should hold if the expression is directly
|
||||
* computed from user input. Such expressions are treated as
|
||||
* sources of taint.
|
||||
*/
|
||||
deprecated predicate isUserInput(Expr expr, string cause) {
|
||||
exists(FunctionCall fc, int i |
|
||||
this.userInputArgument(fc, i) and
|
||||
expr = fc.getArgument(i) and
|
||||
cause = fc.getTarget().getName()
|
||||
)
|
||||
or
|
||||
exists(FunctionCall fc |
|
||||
this.userInputReturned(fc) and
|
||||
expr = fc and
|
||||
cause = fc.getTarget().getName()
|
||||
)
|
||||
or
|
||||
commandLineArg(expr) and cause = "argv"
|
||||
or
|
||||
expr.(EnvironmentRead).getSourceDescription() = cause
|
||||
}
|
||||
|
||||
/**
|
||||
* This predicate should hold if the expression raises privilege for the
|
||||
* current session. The default definition only holds true for some
|
||||
@@ -152,16 +77,6 @@ class SecurityOptions extends string {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to the argv argument to main().
|
||||
*/
|
||||
private predicate commandLineArg(Expr e) {
|
||||
exists(Parameter argv |
|
||||
argv(argv) and
|
||||
argv.getAnAccess() = e
|
||||
)
|
||||
}
|
||||
|
||||
/** The argv parameter to the main function */
|
||||
predicate argv(Parameter argv) {
|
||||
exists(Function f |
|
||||
@@ -173,21 +88,6 @@ predicate argv(Parameter argv) {
|
||||
/** Convenience accessor for SecurityOptions.isPureFunction */
|
||||
predicate isPureFunction(string name) { exists(SecurityOptions opts | opts.isPureFunction(name)) }
|
||||
|
||||
/** Convenience accessor for SecurityOptions.userInputArgument */
|
||||
deprecated predicate userInputArgument(FunctionCall functionCall, int arg) {
|
||||
exists(SecurityOptions opts | opts.userInputArgument(functionCall, arg))
|
||||
}
|
||||
|
||||
/** Convenience accessor for SecurityOptions.userInputReturn */
|
||||
deprecated predicate userInputReturned(FunctionCall functionCall) {
|
||||
exists(SecurityOptions opts | opts.userInputReturned(functionCall))
|
||||
}
|
||||
|
||||
/** Convenience accessor for SecurityOptions.isUserInput */
|
||||
deprecated predicate isUserInput(Expr expr, string cause) {
|
||||
exists(SecurityOptions opts | opts.isUserInput(expr, cause))
|
||||
}
|
||||
|
||||
/** Convenience accessor for SecurityOptions.isProcessOperationArgument */
|
||||
predicate isProcessOperationArgument(string function, int arg) {
|
||||
exists(SecurityOptions opts | opts.isProcessOperationArgument(function, arg))
|
||||
|
||||
@@ -22,28 +22,4 @@ class CustomSecurityOptions extends SecurityOptions {
|
||||
// for example: (function = "MySpecialSqlFunction" and arg = 0)
|
||||
none() // rules to match custom functions replace this line
|
||||
}
|
||||
|
||||
deprecated override predicate userInputArgument(FunctionCall functionCall, int arg) {
|
||||
SecurityOptions.super.userInputArgument(functionCall, arg)
|
||||
or
|
||||
exists(string fname |
|
||||
functionCall.getTarget().hasGlobalName(fname) and
|
||||
exists(functionCall.getArgument(arg)) and
|
||||
// --- custom functions that return user input via one of their arguments:
|
||||
// 'arg' is the 0-based index of the argument that is used to return user input
|
||||
// for example: (fname = "readXmlInto" and arg = 1)
|
||||
none() // rules to match custom functions replace this line
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate userInputReturned(FunctionCall functionCall) {
|
||||
SecurityOptions.super.userInputReturned(functionCall)
|
||||
or
|
||||
exists(string fname |
|
||||
functionCall.getTarget().hasGlobalName(fname) and
|
||||
// --- custom functions that return user input via their return value:
|
||||
// for example: fname = "xmlReadAttribute"
|
||||
none() // rules to match custom functions replace this line
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ module IRFlowTest<IRDataFlow::GlobalFlowSig Flow> implements TestSig {
|
||||
n =
|
||||
strictcount(int line, int column |
|
||||
Flow::flow(any(IRDataFlow::Node otherSource |
|
||||
otherSource.hasLocationInfo(_, line, column, _, _)
|
||||
otherSource.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
), sink)
|
||||
) and
|
||||
(
|
||||
@@ -55,7 +55,7 @@ module AstFlowTest<AstDataFlow::GlobalFlowSig Flow> implements TestSig {
|
||||
n =
|
||||
strictcount(int line, int column |
|
||||
Flow::flow(any(AstDataFlow::Node otherSource |
|
||||
otherSource.hasLocationInfo(_, line, column, _, _)
|
||||
otherSource.getLocation().hasLocationInfo(_, line, column, _, _)
|
||||
), sink)
|
||||
) and
|
||||
(
|
||||
|
||||
@@ -35,6 +35,6 @@ void test_aggregate_literal() {
|
||||
|
||||
S s5 = {.a = 1, .b = 2}; // $ asExpr=1 asExpr=2 asExpr={...}
|
||||
|
||||
int xs[] = {1, 2, 3}; // $ asExpr=1 asExpr=2 asExpr=3 MISSING: asExpr={...}
|
||||
const int ys[] = {[0] = 4, [1] = 5, [0] = 6}; // $ asExpr=4 asExpr=5 asExpr=6 MISSING: asExpr={...}
|
||||
int xs[] = {1, 2, 3}; // $ asExpr=1 asExpr=2 asExpr=3 asExpr={...}
|
||||
const int ys[] = {[0] = 4, [1] = 5, [0] = 6}; // $ asExpr=4 asExpr=5 asExpr=6 asExpr={...}
|
||||
}
|
||||
@@ -2,8 +2,8 @@ edges
|
||||
| consts.cpp:24:7:24:9 | **gv1 | consts.cpp:25:2:25:4 | *a | provenance | |
|
||||
| consts.cpp:24:7:24:9 | **gv1 | consts.cpp:30:9:30:14 | *access to array | provenance | |
|
||||
| consts.cpp:24:7:24:9 | **gv1 | consts.cpp:123:2:123:12 | *... = ... | provenance | |
|
||||
| consts.cpp:25:2:25:4 | *a | consts.cpp:26:2:26:4 | *b | provenance | |
|
||||
| consts.cpp:26:2:26:4 | *b | consts.cpp:24:7:24:9 | **gv1 | provenance | |
|
||||
| consts.cpp:25:2:25:4 | *a | consts.cpp:26:2:26:4 | *{...} | provenance | |
|
||||
| consts.cpp:26:2:26:4 | *{...} | consts.cpp:24:7:24:9 | **gv1 | provenance | |
|
||||
| consts.cpp:29:7:29:25 | **nonConstFuncToArray | consts.cpp:126:9:126:30 | *call to nonConstFuncToArray | provenance | |
|
||||
| consts.cpp:30:9:30:14 | *access to array | consts.cpp:29:7:29:25 | **nonConstFuncToArray | provenance | |
|
||||
| consts.cpp:85:7:85:8 | gets output argument | consts.cpp:86:9:86:10 | *v1 | provenance | |
|
||||
@@ -14,7 +14,7 @@ edges
|
||||
| consts.cpp:85:7:85:8 | gets output argument | consts.cpp:129:19:129:20 | *v1 | provenance | |
|
||||
| consts.cpp:85:7:85:8 | gets output argument | consts.cpp:135:9:135:11 | *v10 | provenance | TaintFunction |
|
||||
| consts.cpp:90:2:90:14 | *... = ... | consts.cpp:91:9:91:10 | *v2 | provenance | |
|
||||
| consts.cpp:90:2:90:14 | *... = ... | consts.cpp:115:21:115:22 | *v2 | provenance | |
|
||||
| consts.cpp:90:2:90:14 | *... = ... | consts.cpp:115:21:115:22 | *{...} | provenance | |
|
||||
| consts.cpp:90:7:90:10 | *call to gets | consts.cpp:90:2:90:14 | *... = ... | provenance | |
|
||||
| consts.cpp:90:12:90:13 | gets output argument | consts.cpp:94:13:94:14 | *v1 | provenance | |
|
||||
| consts.cpp:90:12:90:13 | gets output argument | consts.cpp:99:2:99:8 | *... = ... | provenance | |
|
||||
@@ -28,9 +28,9 @@ edges
|
||||
| consts.cpp:106:13:106:19 | *call to varFunc | consts.cpp:107:9:107:10 | *v5 | provenance | |
|
||||
| consts.cpp:111:2:111:15 | *... = ... | consts.cpp:112:9:112:10 | *v6 | provenance | |
|
||||
| consts.cpp:111:7:111:13 | *call to varFunc | consts.cpp:111:2:111:15 | *... = ... | provenance | |
|
||||
| consts.cpp:115:17:115:18 | *v1 | consts.cpp:115:21:115:22 | *v2 | provenance | |
|
||||
| consts.cpp:115:21:115:22 | *v2 | consts.cpp:116:9:116:13 | *access to array | provenance | |
|
||||
| consts.cpp:115:21:115:22 | *v2 | consts.cpp:120:2:120:11 | *... = ... | provenance | |
|
||||
| consts.cpp:115:17:115:18 | *v1 | consts.cpp:115:21:115:22 | *{...} | provenance | |
|
||||
| consts.cpp:115:21:115:22 | *{...} | consts.cpp:116:9:116:13 | *access to array | provenance | |
|
||||
| consts.cpp:115:21:115:22 | *{...} | consts.cpp:120:2:120:11 | *... = ... | provenance | |
|
||||
| consts.cpp:120:2:120:11 | *... = ... | consts.cpp:121:9:121:10 | *v8 | provenance | |
|
||||
| consts.cpp:123:2:123:12 | *... = ... | consts.cpp:24:7:24:9 | **gv1 | provenance | |
|
||||
| consts.cpp:129:19:129:20 | *v1 | consts.cpp:130:9:130:10 | *v9 | provenance | |
|
||||
@@ -39,7 +39,7 @@ edges
|
||||
nodes
|
||||
| consts.cpp:24:7:24:9 | **gv1 | semmle.label | **gv1 |
|
||||
| consts.cpp:25:2:25:4 | *a | semmle.label | *a |
|
||||
| consts.cpp:26:2:26:4 | *b | semmle.label | *b |
|
||||
| consts.cpp:26:2:26:4 | *{...} | semmle.label | *{...} |
|
||||
| consts.cpp:29:7:29:25 | **nonConstFuncToArray | semmle.label | **nonConstFuncToArray |
|
||||
| consts.cpp:30:9:30:14 | *access to array | semmle.label | *access to array |
|
||||
| consts.cpp:85:7:85:8 | gets output argument | semmle.label | gets output argument |
|
||||
@@ -60,7 +60,7 @@ nodes
|
||||
| consts.cpp:111:7:111:13 | *call to varFunc | semmle.label | *call to varFunc |
|
||||
| consts.cpp:112:9:112:10 | *v6 | semmle.label | *v6 |
|
||||
| consts.cpp:115:17:115:18 | *v1 | semmle.label | *v1 |
|
||||
| consts.cpp:115:21:115:22 | *v2 | semmle.label | *v2 |
|
||||
| consts.cpp:115:21:115:22 | *{...} | semmle.label | *{...} |
|
||||
| consts.cpp:116:9:116:13 | *access to array | semmle.label | *access to array |
|
||||
| consts.cpp:120:2:120:11 | *... = ... | semmle.label | *... = ... |
|
||||
| consts.cpp:121:9:121:10 | *v8 | semmle.label | *v8 |
|
||||
|
||||
@@ -6,8 +6,8 @@ edges
|
||||
| test.cpp:28:10:28:29 | *http://example.com | test.cpp:11:26:11:28 | *url | provenance | |
|
||||
| test.cpp:35:23:35:42 | *http://example.com | test.cpp:35:23:35:42 | *http://example.com | provenance | |
|
||||
| test.cpp:35:23:35:42 | *http://example.com | test.cpp:39:11:39:15 | *url_l | provenance | |
|
||||
| test.cpp:36:26:36:45 | *http://example.com | test.cpp:36:26:36:45 | *http://example.com | provenance | |
|
||||
| test.cpp:36:26:36:45 | *http://example.com | test.cpp:40:11:40:17 | *access to array | provenance | |
|
||||
| test.cpp:36:26:36:45 | *http://example.com | test.cpp:36:26:36:45 | *{...} | provenance | |
|
||||
| test.cpp:36:26:36:45 | *{...} | test.cpp:40:11:40:17 | *access to array | provenance | |
|
||||
| test.cpp:38:11:38:15 | *url_g | test.cpp:11:26:11:28 | *url | provenance | |
|
||||
| test.cpp:39:11:39:15 | *url_l | test.cpp:11:26:11:28 | *url | provenance | |
|
||||
| test.cpp:40:11:40:17 | *access to array | test.cpp:11:26:11:28 | *url | provenance | |
|
||||
@@ -29,7 +29,7 @@ nodes
|
||||
| test.cpp:35:23:35:42 | *http://example.com | semmle.label | *http://example.com |
|
||||
| test.cpp:35:23:35:42 | *http://example.com | semmle.label | *http://example.com |
|
||||
| test.cpp:36:26:36:45 | *http://example.com | semmle.label | *http://example.com |
|
||||
| test.cpp:36:26:36:45 | *http://example.com | semmle.label | *http://example.com |
|
||||
| test.cpp:36:26:36:45 | *{...} | semmle.label | *{...} |
|
||||
| test.cpp:38:11:38:15 | *url_g | semmle.label | *url_g |
|
||||
| test.cpp:39:11:39:15 | *url_l | semmle.label | *url_l |
|
||||
| test.cpp:40:11:40:17 | *access to array | semmle.label | *access to array |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "9.0.100"
|
||||
"version": "9.0.300"
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | $@ flows to here and is written to HTML or JavaScript. | BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | User-provided value |
|
||||
| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | $@ flows to here and is written to HTML or JavaScript. | BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | User-provided value |
|
||||
edges
|
||||
| BlazorTest/Components/Pages/TestPage.razor:85:23:85:32 | access to property QueryParam : String | test-db/working/razor/AC613014E59A413B9538FF8068364499/Microsoft.CodeAnalysis.Razor.Compiler/Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator/Components_Pages_TestPage_razor.g.cs:569:16:577:13 | call to method TypeCheck<String> : String | provenance | Src:MaD:2 MaD:3 |
|
||||
| test-db/working/razor/AC613014E59A413B9538FF8068364499/Microsoft.CodeAnalysis.Razor.Compiler/Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator/Components_Pages_TestPage_razor.g.cs:569:16:577:13 | call to method TypeCheck<String> : String | BlazorTest/Components/MyOutput.razor:5:53:5:57 | access to property Value | provenance | Sink:MaD:1 |
|
||||
| BlazorTest/Components/Pages/TestPage.razor:85:23:85:32 | access to property QueryParam : String | test-db/working/razor/AC613014E59A413B9538FF8068364499/Microsoft.CodeAnalysis.Razor.Compiler/Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator/Components_Pages_TestPage_razor.g.cs:553:16:561:13 | call to method TypeCheck<String> : String | provenance | Src:MaD:2 MaD:3 |
|
||||
| test-db/working/razor/AC613014E59A413B9538FF8068364499/Microsoft.CodeAnalysis.Razor.Compiler/Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator/Components_Pages_TestPage_razor.g.cs:553:16:561:13 | call to method TypeCheck<String> : String | BlazorTest/Components/MyOutput.razor:5:53:5:57 | access to property Value | provenance | Sink:MaD:1 |
|
||||
models
|
||||
| 1 | Sink: Microsoft.AspNetCore.Components; MarkupString; false; MarkupString; (System.String); ; Argument[0]; html-injection; manual |
|
||||
| 2 | Source: Microsoft.AspNetCore.Components; SupplyParameterFromQueryAttribute; false; ; ; Attribute.Getter; ReturnValue; remote; manual |
|
||||
@@ -14,5 +14,5 @@ nodes
|
||||
| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | semmle.label | access to property UrlParam |
|
||||
| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | semmle.label | access to property QueryParam |
|
||||
| BlazorTest/Components/Pages/TestPage.razor:85:23:85:32 | access to property QueryParam : String | semmle.label | access to property QueryParam : String |
|
||||
| test-db/working/razor/AC613014E59A413B9538FF8068364499/Microsoft.CodeAnalysis.Razor.Compiler/Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator/Components_Pages_TestPage_razor.g.cs:569:16:577:13 | call to method TypeCheck<String> : String | semmle.label | call to method TypeCheck<String> : String |
|
||||
| test-db/working/razor/AC613014E59A413B9538FF8068364499/Microsoft.CodeAnalysis.Razor.Compiler/Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator/Components_Pages_TestPage_razor.g.cs:553:16:561:13 | call to method TypeCheck<String> : String | semmle.label | call to method TypeCheck<String> : String |
|
||||
subpaths
|
||||
|
||||
@@ -38,7 +38,6 @@ ql/csharp/ql/src/Concurrency/SynchSetUnsynchGet.ql
|
||||
ql/csharp/ql/src/Concurrency/UnsafeLazyInitialization.ql
|
||||
ql/csharp/ql/src/Concurrency/UnsynchronizedStaticAccess.ql
|
||||
ql/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql
|
||||
ql/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql
|
||||
ql/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
|
||||
ql/csharp/ql/src/Diagnostics/CompilerError.ql
|
||||
ql/csharp/ql/src/Diagnostics/CompilerMessage.ql
|
||||
@@ -146,8 +145,6 @@ ql/csharp/ql/src/Security Features/CWE-639/InsecureDirectObjectReference.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-730/ReDoS.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql
|
||||
ql/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql
|
||||
ql/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
ql/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql
|
||||
ql/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql
|
||||
ql/csharp/ql/src/Diagnostics/CompilerError.ql
|
||||
ql/csharp/ql/src/Diagnostics/CompilerMessage.ql
|
||||
ql/csharp/ql/src/Diagnostics/DiagnosticExtractionErrors.ql
|
||||
@@ -49,8 +48,6 @@ ql/csharp/ql/src/Security Features/CWE-639/InsecureDirectObjectReference.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-730/ReDoS.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql
|
||||
ql/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql
|
||||
ql/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql
|
||||
|
||||
@@ -26,6 +26,7 @@ ql/csharp/ql/src/Bad Practices/Naming Conventions/DefaultControlNames.ql
|
||||
ql/csharp/ql/src/Bad Practices/Naming Conventions/VariableNameTooShort.ql
|
||||
ql/csharp/ql/src/Bad Practices/UseOfHtmlInputHidden.ql
|
||||
ql/csharp/ql/src/Bad Practices/UseOfSystemOutputStream.ql
|
||||
ql/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql
|
||||
ql/csharp/ql/src/Dead Code/DeadRefTypes.ql
|
||||
ql/csharp/ql/src/Dead Code/NonAssignedFields.ql
|
||||
ql/csharp/ql/src/Dead Code/UnusedField.ql
|
||||
@@ -89,6 +90,8 @@ ql/csharp/ql/src/Security Features/CWE-321/HardcodedSymmetricEncryptionKey.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-327/DontInstallRootCert.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql
|
||||
ql/csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql
|
||||
ql/csharp/ql/src/Useless code/PointlessForwardingMethod.ql
|
||||
ql/csharp/ql/src/definitions.ql
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.5
|
||||
* @precision medium
|
||||
* @precision low
|
||||
* @id cs/password-in-configuration
|
||||
* @tags security
|
||||
* external/cwe/cwe-013
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.8
|
||||
* @precision medium
|
||||
* @precision low
|
||||
* @id cs/hardcoded-connection-string-credentials
|
||||
* @tags security
|
||||
* external/cwe/cwe-259
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.8
|
||||
* @precision medium
|
||||
* @precision low
|
||||
* @id cs/hardcoded-credentials
|
||||
* @tags security
|
||||
* external/cwe/cwe-259
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The queries `cs/password-in-configuration`, `cs/hardcoded-credentials` and `cs/hardcoded-connection-string-credentials` have been removed from all query suites.
|
||||
@@ -35,7 +35,7 @@ Bug Fixes
|
||||
GitHub Actions
|
||||
""""""""""""""
|
||||
|
||||
* The :code:`actions/unversioned-immutable-action` query will no longer report any alerts, since the Immutable Actions feature is not yet available for customer use. The query remains in the default Code Scanning suites for use internal to GitHub. Once the Immutable Actions feature is available, the query will be updated to report alerts again.
|
||||
* The :code:`actions/unversioned-immutable-action` query will no longer report any alerts, since the Immutable Actions feature is not yet available for customer use. The query has also been moved to the experimental folder and will not be used in code scanning unless it is explicitly added to a code scanning configuration. Once the Immutable Actions feature is available, the query will be updated to report alerts again.
|
||||
|
||||
Major Analysis Improvements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -37,14 +37,6 @@ Bug Fixes
|
||||
Query Packs
|
||||
-----------
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
GitHub Actions
|
||||
""""""""""""""
|
||||
|
||||
* CodeQL and Copilot Autofix support for GitHub Actions is now Generally Available.
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
@@ -87,6 +79,14 @@ Python
|
||||
|
||||
* The :code:`py/mixed-tuple-returns` query no longer flags instances where the tuple is passed into the function as an argument, as this led to too many false positives.
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
GitHub Actions
|
||||
""""""""""""""
|
||||
|
||||
* CodeQL and Copilot Autofix support for GitHub Actions is now Generally Available.
|
||||
|
||||
Language Libraries
|
||||
------------------
|
||||
|
||||
@@ -131,17 +131,17 @@ Ruby
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
GitHub Actions
|
||||
""""""""""""""
|
||||
|
||||
* CodeQL and Copilot Autofix support for GitHub Actions is now Generally Available.
|
||||
|
||||
C/C++
|
||||
"""""
|
||||
|
||||
* Calling conventions explicitly specified on function declarations (:code:`__cdecl`, :code:`__stdcall`, :code:`__fastcall`, etc.) are now represented as specifiers of those declarations.
|
||||
* A new class :code:`CallingConventionSpecifier` extending the :code:`Specifier` class was introduced, which represents explicitly specified calling conventions.
|
||||
|
||||
GitHub Actions
|
||||
""""""""""""""
|
||||
|
||||
* CodeQL and Copilot Autofix support for GitHub Actions is now Generally Available.
|
||||
|
||||
Shared Libraries
|
||||
----------------
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
.. _codeql-cli-2.21.3:
|
||||
|
||||
==========================
|
||||
CodeQL 2.21.3 (2025-05-15)
|
||||
==========================
|
||||
|
||||
.. 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.21.3 runs a total of 452 security queries when configured with the Default suite (covering 168 CWE). The Extended suite enables an additional 136 queries (covering 35 more CWE).
|
||||
|
||||
CodeQL CLI
|
||||
----------
|
||||
|
||||
Miscellaneous
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
* Windows binaries for the CodeQL CLI are now built with :code:`/guard:cf`, enabling `Control Flow Guard <https://learn.microsoft.com/en-us/windows/win32/secbp/control-flow-guard>`__.
|
||||
|
||||
Query Packs
|
||||
-----------
|
||||
|
||||
Minor Analysis Improvements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
C#
|
||||
""
|
||||
|
||||
* Changed the precision of the :code:`cs/equality-on-floats` query from medium to high.
|
||||
|
||||
JavaScript/TypeScript
|
||||
"""""""""""""""""""""
|
||||
|
||||
* Type information is now propagated more precisely through :code:`Promise.all()` calls,
|
||||
leading to more resolved calls and more sources and sinks being detected.
|
||||
|
||||
Query Metadata Changes
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
C/C++
|
||||
"""""
|
||||
|
||||
* The tag :code:`external/cwe/cwe-14` has been removed from :code:`cpp/memset-may-be-deleted` and the tag :code:`external/cwe/cwe-014` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`cpp/count-untrusted-data-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`cpp/count-untrusted-data-external-api-ir` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`cpp/untrusted-data-to-external-api-ir` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`cpp/untrusted-data-to-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`cpp/late-check-of-function-argument` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
|
||||
C#
|
||||
""
|
||||
|
||||
* The tag :code:`external/cwe/cwe-13` has been removed from :code:`cs/password-in-configuration` and the tag :code:`external/cwe/cwe-013` has been added.
|
||||
* The tag :code:`external/cwe/cwe-11` has been removed from :code:`cs/web/debug-binary` and the tag :code:`external/cwe/cwe-011` has been added.
|
||||
* The tag :code:`external/cwe/cwe-16` has been removed from :code:`cs/web/large-max-request-length` and the tag :code:`external/cwe/cwe-016` has been added.
|
||||
* The tag :code:`external/cwe/cwe-16` has been removed from :code:`cs/web/request-validation-disabled` and the tag :code:`external/cwe/cwe-016` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`cs/count-untrusted-data-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`cs/serialization-check-bypass` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`cs/untrusted-data-to-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-12` has been removed from :code:`cs/web/missing-global-error-handler` and the tag :code:`external/cwe/cwe-012` has been added.
|
||||
|
||||
Golang
|
||||
""""""
|
||||
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`go/count-untrusted-data-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`go/incomplete-hostname-regexp` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`go/regex/missing-regexp-anchor` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`go/suspicious-character-in-regex` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`go/untrusted-data-to-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`go/untrusted-data-to-unknown-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-90` has been removed from :code:`go/ldap-injection` and the tag :code:`external/cwe/cwe-090` has been added.
|
||||
* The tag :code:`external/cwe/cwe-74` has been removed from :code:`go/dsn-injection` and the tag :code:`external/cwe/cwe-074` has been added.
|
||||
* The tag :code:`external/cwe/cwe-74` has been removed from :code:`go/dsn-injection-local` and the tag :code:`external/cwe/cwe-074` has been added.
|
||||
* The tag :code:`external/cwe/cwe-79` has been removed from :code:`go/html-template-escaping-passthrough` and the tag :code:`external/cwe/cwe-079` has been added.
|
||||
|
||||
Java/Kotlin
|
||||
"""""""""""
|
||||
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`java/count-untrusted-data-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`java/untrusted-data-to-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-93` has been removed from :code:`java/netty-http-request-or-response-splitting` and the tag :code:`external/cwe/cwe-093` has been added.
|
||||
|
||||
JavaScript/TypeScript
|
||||
"""""""""""""""""""""
|
||||
|
||||
* The tag :code:`external/cwe/cwe-79` has been removed from :code:`js/disabling-electron-websecurity` and the tag :code:`external/cwe/cwe-079` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`js/count-untrusted-data-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`js/untrusted-data-to-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`js/untrusted-data-to-external-api-more-sources` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
|
||||
Python
|
||||
""""""
|
||||
|
||||
* The tags :code:`security/cwe/cwe-94` and :code:`security/cwe/cwe-95` have been removed from :code:`py/use-of-input` and the tags :code:`external/cwe/cwe-094` and :code:`external/cwe/cwe-095` have been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`py/count-untrusted-data-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`py/untrusted-data-to-external-api` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`py/cookie-injection` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-20` has been removed from :code:`py/incomplete-url-substring-sanitization` and the tag :code:`external/cwe/cwe-020` has been added.
|
||||
* The tag :code:`external/cwe/cwe-94` has been removed from :code:`py/js2py-rce` and the tag :code:`external/cwe/cwe-094` has been added.
|
||||
|
||||
Ruby
|
||||
""""
|
||||
|
||||
* The precision of :code:`rb/useless-assignment-to-local` has been adjusted from :code:`medium` to :code:`high`.
|
||||
* The tag :code:`external/cwe/cwe-94` has been removed from :code:`rb/server-side-template-injection` and the tag :code:`external/cwe/cwe-094` has been added.
|
||||
|
||||
Language Libraries
|
||||
------------------
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
C/C++
|
||||
"""""
|
||||
|
||||
* Fixed an infinite loop in :code:`semmle.code.cpp.rangeanalysis.new.RangeAnalysis` when computing ranges in very large and complex function bodies.
|
||||
|
||||
Minor Analysis Improvements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
JavaScript/TypeScript
|
||||
"""""""""""""""""""""
|
||||
|
||||
* Enhanced modeling of the `fastify <https://www.npmjs.com/package/fastify>`__ framework to support the :code:`all` route handler method.
|
||||
* Improved modeling of the |link-code-shelljs-1|_ and |link-code-async-shelljs-2|_ libraries by adding support for the :code:`which`, :code:`cmd`, :code:`asyncExec` and :code:`env`.
|
||||
* Added support for the :code:`fastify` :code:`addHook` method.
|
||||
|
||||
Python
|
||||
""""""
|
||||
|
||||
* Added modeling for the :code:`hdbcli` PyPI package as a database library implementing PEP 249.
|
||||
* Added header write model for :code:`send_header` in :code:`http.server`.
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Java/Kotlin
|
||||
"""""""""""
|
||||
|
||||
* Kotlin versions up to 2.2.0\ *x* are now supported. Support for the Kotlin 1.5.x series is dropped (so the minimum Kotlin version is now 1.6.0).
|
||||
|
||||
Swift
|
||||
"""""
|
||||
|
||||
* Added AST nodes :code:`UnsafeCastExpr`, :code:`TypeValueExpr`, :code:`IntegerType`, and :code:`BuiltinFixedArrayType` that correspond to new nodes added by Swift 6.1.
|
||||
|
||||
.. |link-code-shelljs-1| replace:: :code:`shelljs`\
|
||||
.. _link-code-shelljs-1: https://www.npmjs.com/package/shelljs
|
||||
|
||||
.. |link-code-async-shelljs-2| replace:: :code:`async-shelljs`\
|
||||
.. _link-code-async-shelljs-2: https://www.npmjs.com/package/async-shelljs
|
||||
|
||||
@@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here <https://docs.g
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
codeql-cli-2.21.3
|
||||
codeql-cli-2.21.2
|
||||
codeql-cli-2.21.1
|
||||
codeql-cli-2.21.0
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [8]_"
|
||||
Python [9]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py``
|
||||
Ruby [10]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"
|
||||
Swift [11]_,"Swift 5.4-6.0","Swift compiler","``.swift``"
|
||||
Swift [11]_,"Swift 5.4-6.1","Swift compiler","``.swift``"
|
||||
TypeScript [12]_,"2.6-5.8",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``"
|
||||
|
||||
.. container:: footnote-group
|
||||
|
||||
@@ -50,6 +50,5 @@ ql/go/ql/src/Security/CWE-640/EmailInjection.ql
|
||||
ql/go/ql/src/Security/CWE-643/XPathInjection.ql
|
||||
ql/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql
|
||||
ql/go/ql/src/Security/CWE-770/UncontrolledAllocationSize.ql
|
||||
ql/go/ql/src/Security/CWE-798/HardcodedCredentials.ql
|
||||
ql/go/ql/src/Security/CWE-918/RequestForgery.ql
|
||||
ql/go/ql/src/Summary/LinesOfCode.ql
|
||||
|
||||
@@ -28,6 +28,5 @@ ql/go/ql/src/Security/CWE-640/EmailInjection.ql
|
||||
ql/go/ql/src/Security/CWE-643/XPathInjection.ql
|
||||
ql/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql
|
||||
ql/go/ql/src/Security/CWE-770/UncontrolledAllocationSize.ql
|
||||
ql/go/ql/src/Security/CWE-798/HardcodedCredentials.ql
|
||||
ql/go/ql/src/Security/CWE-918/RequestForgery.ql
|
||||
ql/go/ql/src/Summary/LinesOfCode.ql
|
||||
|
||||
@@ -6,6 +6,7 @@ ql/go/ql/src/Security/CWE-020/UntrustedDataToExternalAPI.ql
|
||||
ql/go/ql/src/Security/CWE-020/UntrustedDataToUnknownExternalAPI.ql
|
||||
ql/go/ql/src/Security/CWE-078/StoredCommand.ql
|
||||
ql/go/ql/src/Security/CWE-079/StoredXss.ql
|
||||
ql/go/ql/src/Security/CWE-798/HardcodedCredentials.ql
|
||||
ql/go/ql/src/definitions.ql
|
||||
ql/go/ql/src/experimental/CWE-090/LDAPInjection.ql
|
||||
ql/go/ql/src/experimental/CWE-1004/CookieWithoutHttpOnly.ql
|
||||
|
||||
@@ -30,10 +30,6 @@ No user-facing changes.
|
||||
|
||||
* The member predicate `hasLocationInfo` has been deprecated on the following classes: `BasicBlock`, `Callable`, `Content`, `ContentSet`, `ControlFlow::Node`, `DataFlowCallable`, `DataFlow::Node`, `Entity`, `GVN`, `HtmlTemplate::TemplateStmt`, `IR:WriteTarget`, `SourceSinkInterpretationInput::SourceOrSinkElement`, `SourceSinkInterpretationInput::InterpretNode`, `SsaVariable`, `SsaDefinition`, `SsaWithFields`, `StringOps::ConcatenationElement`, `Type`, and `VariableWithFields`. Use `getLocation()` instead.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Go 1.24 is now supported. This includes the new language feature of generic type aliases.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The location info for the following classes has been changed slightly to match a location that is in the database: `BasicBlock`, `ControlFlow::EntryNode`, `ControlFlow::ExitNode`, `ControlFlow::ConditionGuardNode`, `IR::ImplicitLiteralElementIndexInstruction`, `IR::EvalImplicitTrueInstruction`, `SsaImplicitDefinition`, `SsaPhiNode`.
|
||||
@@ -48,6 +44,10 @@ No user-facing changes.
|
||||
* The member predicate `getNamedType` on `GoMicro::ServiceInterfaceType` has been deprecated. Use the new member predicate `getDefinedType` instead.
|
||||
* The member predicate `getNamedType` on `Twirp::ServiceInterfaceType` has been deprecated. Use the new member predicate `getDefinedType` instead.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Go 1.24 is now supported. This includes the new language feature of generic type aliases.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Taint models have been added for the `weak` package, which was added in Go 1.24.
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
* The member predicate `getNamedType` on `GoMicro::ServiceInterfaceType` has been deprecated. Use the new member predicate `getDefinedType` instead.
|
||||
* The member predicate `getNamedType` on `Twirp::ServiceInterfaceType` has been deprecated. Use the new member predicate `getDefinedType` instead.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Go 1.24 is now supported. This includes the new language feature of generic type aliases.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Taint models have been added for the `weak` package, which was added in Go 1.24.
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
|
||||
* The member predicate `hasLocationInfo` has been deprecated on the following classes: `BasicBlock`, `Callable`, `Content`, `ContentSet`, `ControlFlow::Node`, `DataFlowCallable`, `DataFlow::Node`, `Entity`, `GVN`, `HtmlTemplate::TemplateStmt`, `IR:WriteTarget`, `SourceSinkInterpretationInput::SourceOrSinkElement`, `SourceSinkInterpretationInput::InterpretNode`, `SsaVariable`, `SsaDefinition`, `SsaWithFields`, `StringOps::ConcatenationElement`, `Type`, and `VariableWithFields`. Use `getLocation()` instead.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Go 1.24 is now supported. This includes the new language feature of generic type aliases.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The location info for the following classes has been changed slightly to match a location that is in the database: `BasicBlock`, `ControlFlow::EntryNode`, `ControlFlow::ExitNode`, `ControlFlow::ConditionGuardNode`, `IR::ImplicitLiteralElementIndexInstruction`, `IR::EvalImplicitTrueInstruction`, `SsaImplicitDefinition`, `SsaPhiNode`.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.8
|
||||
* @precision medium
|
||||
* @precision low
|
||||
* @id go/hardcoded-credentials
|
||||
* @tags security
|
||||
* external/cwe/cwe-259
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `go/hardcoded-credentials` has been removed from all query suites.
|
||||
@@ -196,7 +196,6 @@ ql/java/ql/src/Security/CWE/CWE-730/RegexInjection.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-749/UnsafeAndroidAccess.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql
|
||||
|
||||
@@ -99,7 +99,6 @@ ql/java/ql/src/Security/CWE/CWE-730/RegexInjection.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-749/UnsafeAndroidAccess.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql
|
||||
|
||||
@@ -158,6 +158,7 @@ ql/java/ql/src/Security/CWE/CWE-312/CleartextStorageClass.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-319/UseSSL.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-319/UseSSLSocketFactories.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsComparison.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsSourceCall.ql
|
||||
ql/java/ql/src/Security/CWE/CWE-798/HardcodedPasswordField.ql
|
||||
|
||||
@@ -20,7 +20,7 @@ No user-facing changes.
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Java extraction is now able to download Maven 3.9.x if a Maven Enforcer Plugin configuration indicates it is necessary. Maven 3.8.x is still preferred if the enforcer-plugin configuration (if any) permits it.
|
||||
* Added a path injection sanitizer for calls to `java.lang.String.matches`, `java.lang.String.replace`, and `java.lang.String.replaceAll` that make sure '/', '\', '..' are not in the path.
|
||||
* Added a path injection sanitizer for calls to `java.lang.String.matches`, `java.lang.String.replace`, and `java.lang.String.replaceAll` that make sure `/`, `\\`, `..` are not in the path.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -55,8 +55,8 @@ No user-facing changes.
|
||||
* Deleted the deprecated `isLValue` and `isRValue` predicates from the `VarAccess` class, use `isVarWrite` and `isVarRead` respectively instead.
|
||||
* Deleted the deprecated `getRhs` predicate from the `VarWrite` class, use `getASource` instead.
|
||||
* Deleted the deprecated `LValue` and `RValue` classes, use `VarWrite` and `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 `*Access`, use the corresponding `*Call` classes instead.
|
||||
* Deleted a lot of deprecated predicates ending in `*Access`, use the corresponding `*Call` predicates instead.
|
||||
* Deleted the deprecated `EnvInput` and `DatabaseInput` classes from `FlowSources.qll`, use the threat models feature instead.
|
||||
* Deleted some deprecated API predicates from `SensitiveApi.qll`, use the Sink classes from that file instead.
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* Java now uses the shared `BasicBlock` library. This means that the names of several member predicates have been changed to align with the names used in other languages. The old predicates have been deprecated. The `BasicBlock` class itself no longer extends `ControlFlowNode` - the predicate `getFirstNode` can be used to fix any QL code that somehow relied on this.
|
||||
@@ -5,8 +5,8 @@
|
||||
* Deleted the deprecated `isLValue` and `isRValue` predicates from the `VarAccess` class, use `isVarWrite` and `isVarRead` respectively instead.
|
||||
* Deleted the deprecated `getRhs` predicate from the `VarWrite` class, use `getASource` instead.
|
||||
* Deleted the deprecated `LValue` and `RValue` classes, use `VarWrite` and `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 `*Access`, use the corresponding `*Call` classes instead.
|
||||
* Deleted a lot of deprecated predicates ending in `*Access`, use the corresponding `*Call` predicates instead.
|
||||
* Deleted the deprecated `EnvInput` and `DatabaseInput` classes from `FlowSources.qll`, use the threat models feature instead.
|
||||
* Deleted some deprecated API predicates from `SensitiveApi.qll`, use the Sink classes from that file instead.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Java extraction is now able to download Maven 3.9.x if a Maven Enforcer Plugin configuration indicates it is necessary. Maven 3.8.x is still preferred if the enforcer-plugin configuration (if any) permits it.
|
||||
* Added a path injection sanitizer for calls to `java.lang.String.matches`, `java.lang.String.replace`, and `java.lang.String.replaceAll` that make sure '/', '\', '..' are not in the path.
|
||||
* Added a path injection sanitizer for calls to `java.lang.String.matches`, `java.lang.String.replace`, and `java.lang.String.replaceAll` that make sure `/`, `\\`, `..` are not in the path.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
||||
@@ -1606,13 +1606,8 @@ module JCAModel {
|
||||
else result = Crypto::OtherEllipticCurveType()
|
||||
}
|
||||
|
||||
override string getKeySize() {
|
||||
exists(int keySize |
|
||||
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), keySize,
|
||||
_)
|
||||
|
|
||||
result = keySize.toString()
|
||||
)
|
||||
override int getKeySize() {
|
||||
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), result, _)
|
||||
}
|
||||
|
||||
EllipticCurveAlgorithmValueConsumer getConsumer() { result = consumer }
|
||||
|
||||
@@ -6,6 +6,7 @@ extractor: java
|
||||
library: true
|
||||
upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/controlflow: ${workspace}
|
||||
codeql/dataflow: ${workspace}
|
||||
codeql/mad: ${workspace}
|
||||
codeql/quantum: ${workspace}
|
||||
|
||||
@@ -4,91 +4,128 @@
|
||||
|
||||
import java
|
||||
import Dominance
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
cached
|
||||
private module BasicBlockStage {
|
||||
cached
|
||||
predicate ref() { any() }
|
||||
private module Input implements BB::InputSig<Location> {
|
||||
import SuccessorType
|
||||
|
||||
cached
|
||||
predicate backref() {
|
||||
(exists(any(BasicBlock bb).getABBSuccessor()) implies any()) and
|
||||
(exists(any(BasicBlock bb).getNode(_)) implies any()) and
|
||||
(exists(any(BasicBlock bb).length()) implies any())
|
||||
/** Hold if `t` represents a conditional successor type. */
|
||||
predicate successorTypeIsCondition(SuccessorType t) { none() }
|
||||
|
||||
/** A delineated part of the AST with its own CFG. */
|
||||
class CfgScope = Callable;
|
||||
|
||||
/** The class of control flow nodes. */
|
||||
class Node = ControlFlowNode;
|
||||
|
||||
/** Gets the CFG scope in which this node occurs. */
|
||||
CfgScope nodeGetCfgScope(Node node) { node.getEnclosingCallable() = result }
|
||||
|
||||
private Node getASpecificSuccessor(Node node, SuccessorType t) {
|
||||
node.(ConditionNode).getABranchSuccessor(t.(BooleanSuccessor).getValue()) = result
|
||||
or
|
||||
node.getAnExceptionSuccessor() = result and t instanceof ExceptionSuccessor
|
||||
}
|
||||
|
||||
/** Gets an immediate successor of this node. */
|
||||
Node nodeGetASuccessor(Node node, SuccessorType t) {
|
||||
result = getASpecificSuccessor(node, t)
|
||||
or
|
||||
node.getASuccessor() = result and
|
||||
t instanceof NormalSuccessor and
|
||||
not result = getASpecificSuccessor(node, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` represents an entry node to be used when calculating
|
||||
* dominance.
|
||||
*/
|
||||
predicate nodeIsDominanceEntry(Node node) {
|
||||
exists(Stmt entrystmt | entrystmt = node.asStmt() |
|
||||
exists(Callable c | entrystmt = c.getBody())
|
||||
or
|
||||
// This disjunct is technically superfluous, but safeguards against extractor problems.
|
||||
entrystmt instanceof BlockStmt and
|
||||
not exists(entrystmt.getEnclosingCallable()) and
|
||||
not entrystmt.getParent() instanceof Stmt
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` represents an exit node to be used when calculating
|
||||
* post dominance.
|
||||
*/
|
||||
predicate nodeIsPostDominanceExit(Node node) { node instanceof ControlFlow::ExitNode }
|
||||
}
|
||||
|
||||
private module BbImpl = BB::Make<Location, Input>;
|
||||
|
||||
import BbImpl
|
||||
|
||||
/** Holds if the dominance relation is calculated for `bb`. */
|
||||
predicate hasDominanceInformation(BasicBlock bb) {
|
||||
exists(BasicBlock entry |
|
||||
Input::nodeIsDominanceEntry(entry.getFirstNode()) and entry.getASuccessor*() = bb
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A control-flow node that represents the start of a basic block.
|
||||
*
|
||||
* A basic block is a series of nodes with no control-flow branching, which can
|
||||
* often be treated as a unit in analyses.
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
*/
|
||||
class BasicBlock extends ControlFlowNode {
|
||||
cached
|
||||
BasicBlock() {
|
||||
BasicBlockStage::ref() and
|
||||
not exists(this.getAPredecessor()) and
|
||||
exists(this.getASuccessor())
|
||||
or
|
||||
strictcount(this.getAPredecessor()) > 1
|
||||
or
|
||||
exists(ControlFlowNode pred | pred = this.getAPredecessor() |
|
||||
strictcount(pred.getASuccessor()) > 1
|
||||
)
|
||||
}
|
||||
class BasicBlock extends BbImpl::BasicBlock {
|
||||
/** Gets the immediately enclosing callable whose body contains this node. */
|
||||
Callable getEnclosingCallable() { result = this.getScope() }
|
||||
|
||||
/** Gets an immediate successor of this basic block. */
|
||||
cached
|
||||
BasicBlock getABBSuccessor() {
|
||||
BasicBlockStage::ref() and
|
||||
result = this.getLastNode().getASuccessor()
|
||||
}
|
||||
/**
|
||||
* Holds if this basic block dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching `bb` from the entry point basic block must
|
||||
* go through this basic block.
|
||||
*/
|
||||
predicate dominates(BasicBlock bb) { super.dominates(bb) }
|
||||
|
||||
/** Gets an immediate predecessor of this basic block. */
|
||||
BasicBlock getABBPredecessor() { result.getABBSuccessor() = this }
|
||||
/**
|
||||
* DEPRECATED: Use `getASuccessor` instead.
|
||||
*
|
||||
* Gets an immediate successor of this basic block.
|
||||
*/
|
||||
deprecated BasicBlock getABBSuccessor() { result = this.getASuccessor() }
|
||||
|
||||
/** Gets a control-flow node contained in this basic block. */
|
||||
ControlFlowNode getANode() { result = this.getNode(_) }
|
||||
/**
|
||||
* DEPRECATED: Use `getAPredecessor` instead.
|
||||
*
|
||||
* Gets an immediate predecessor of this basic block.
|
||||
*/
|
||||
deprecated BasicBlock getABBPredecessor() { result.getASuccessor() = this }
|
||||
|
||||
/** Gets the control-flow node at a specific (zero-indexed) position in this basic block. */
|
||||
cached
|
||||
ControlFlowNode getNode(int pos) {
|
||||
BasicBlockStage::ref() and
|
||||
result = this and
|
||||
pos = 0
|
||||
or
|
||||
exists(ControlFlowNode mid, int mid_pos | pos = mid_pos + 1 |
|
||||
this.getNode(mid_pos) = mid and
|
||||
mid.getASuccessor() = result and
|
||||
not result instanceof BasicBlock
|
||||
)
|
||||
}
|
||||
/**
|
||||
* DEPRECATED: Use `strictlyDominates` instead.
|
||||
*
|
||||
* Holds if this basic block strictly dominates `node`.
|
||||
*/
|
||||
deprecated predicate bbStrictlyDominates(BasicBlock node) { this.strictlyDominates(node) }
|
||||
|
||||
/** Gets the first control-flow node in this basic block. */
|
||||
ControlFlowNode getFirstNode() { result = this }
|
||||
/**
|
||||
* DEPRECATED: Use `dominates` instead.
|
||||
*
|
||||
* Holds if this basic block dominates `node`. (This is reflexive.)
|
||||
*/
|
||||
deprecated predicate bbDominates(BasicBlock node) { this.dominates(node) }
|
||||
|
||||
/** Gets the last control-flow node in this basic block. */
|
||||
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
|
||||
/**
|
||||
* DEPRECATED: Use `strictlyPostDominates` instead.
|
||||
*
|
||||
* Holds if this basic block strictly post-dominates `node`.
|
||||
*/
|
||||
deprecated predicate bbStrictlyPostDominates(BasicBlock node) { this.strictlyPostDominates(node) }
|
||||
|
||||
/** Gets the number of control-flow nodes contained in this basic block. */
|
||||
cached
|
||||
int length() {
|
||||
BasicBlockStage::ref() and
|
||||
result = strictcount(this.getANode())
|
||||
}
|
||||
|
||||
/** Holds if this basic block strictly dominates `node`. */
|
||||
predicate bbStrictlyDominates(BasicBlock node) { bbStrictlyDominates(this, node) }
|
||||
|
||||
/** Holds if this basic block dominates `node`. (This is reflexive.) */
|
||||
predicate bbDominates(BasicBlock node) { bbDominates(this, node) }
|
||||
|
||||
/** Holds if this basic block strictly post-dominates `node`. */
|
||||
predicate bbStrictlyPostDominates(BasicBlock node) { bbStrictlyPostDominates(this, node) }
|
||||
|
||||
/** Holds if this basic block post-dominates `node`. (This is reflexive.) */
|
||||
predicate bbPostDominates(BasicBlock node) { bbPostDominates(this, node) }
|
||||
/**
|
||||
* DEPRECATED: Use `postDominates` instead.
|
||||
*
|
||||
* Holds if this basic block post-dominates `node`. (This is reflexive.)
|
||||
*/
|
||||
deprecated predicate bbPostDominates(BasicBlock node) { this.postDominates(node) }
|
||||
}
|
||||
|
||||
/** A basic block that ends in an exit node. */
|
||||
|
||||
@@ -8,91 +8,75 @@ import java
|
||||
* Predicates for basic-block-level dominance.
|
||||
*/
|
||||
|
||||
/** Entry points for control-flow. */
|
||||
private predicate flowEntry(BasicBlock entry) {
|
||||
exists(Stmt entrystmt | entrystmt = entry.getFirstNode().asStmt() |
|
||||
exists(Callable c | entrystmt = c.getBody())
|
||||
or
|
||||
// This disjunct is technically superfluous, but safeguards against extractor problems.
|
||||
entrystmt instanceof BlockStmt and
|
||||
not exists(entry.getEnclosingCallable()) and
|
||||
not entrystmt.getParent() instanceof Stmt
|
||||
)
|
||||
}
|
||||
|
||||
/** The successor relation for basic blocks. */
|
||||
private predicate bbSucc(BasicBlock pre, BasicBlock post) { post = pre.getABBSuccessor() }
|
||||
|
||||
/** The immediate dominance relation for basic blocks. */
|
||||
cached
|
||||
predicate bbIDominates(BasicBlock dom, BasicBlock node) =
|
||||
idominance(flowEntry/1, bbSucc/2)(_, dom, node)
|
||||
|
||||
/** Holds if the dominance relation is calculated for `bb`. */
|
||||
predicate hasDominanceInformation(BasicBlock bb) {
|
||||
exists(BasicBlock entry | flowEntry(entry) and bbSucc*(entry, bb))
|
||||
/**
|
||||
* DEPRECATED: Use `BasicBlock::immediatelyDominates` instead.
|
||||
*
|
||||
* The immediate dominance relation for basic blocks.
|
||||
*/
|
||||
deprecated predicate bbIDominates(BasicBlock dom, BasicBlock node) {
|
||||
dom.immediatelyDominates(node)
|
||||
}
|
||||
|
||||
/** Exit points for basic-block control-flow. */
|
||||
private predicate bbSink(BasicBlock exit) { exit.getLastNode() instanceof ControlFlow::ExitNode }
|
||||
|
||||
/** Reversed `bbSucc`. */
|
||||
private predicate bbPred(BasicBlock post, BasicBlock pre) { post = pre.getABBSuccessor() }
|
||||
private predicate bbPred(BasicBlock post, BasicBlock pre) { post = pre.getASuccessor() }
|
||||
|
||||
/** The immediate post-dominance relation on basic blocks. */
|
||||
cached
|
||||
predicate bbIPostDominates(BasicBlock dominator, BasicBlock node) =
|
||||
deprecated predicate bbIPostDominates(BasicBlock dominator, BasicBlock node) =
|
||||
idominance(bbSink/1, bbPred/2)(_, dominator, node)
|
||||
|
||||
/** Holds if `dom` strictly dominates `node`. */
|
||||
predicate bbStrictlyDominates(BasicBlock dom, BasicBlock node) { bbIDominates+(dom, node) }
|
||||
|
||||
/** Holds if `dom` dominates `node`. (This is reflexive.) */
|
||||
predicate bbDominates(BasicBlock dom, BasicBlock node) {
|
||||
bbStrictlyDominates(dom, node) or dom = node
|
||||
/**
|
||||
* DEPRECATED: Use `BasicBlock::strictlyDominates` instead.
|
||||
*
|
||||
* Holds if `dom` strictly dominates `node`.
|
||||
*/
|
||||
deprecated predicate bbStrictlyDominates(BasicBlock dom, BasicBlock node) {
|
||||
dom.strictlyDominates(node)
|
||||
}
|
||||
|
||||
/** Holds if `dom` strictly post-dominates `node`. */
|
||||
predicate bbStrictlyPostDominates(BasicBlock dom, BasicBlock node) { bbIPostDominates+(dom, node) }
|
||||
/**
|
||||
* DEPRECATED: Use `BasicBlock::dominates` instead.
|
||||
*
|
||||
* Holds if `dom` dominates `node`. (This is reflexive.)
|
||||
*/
|
||||
deprecated predicate bbDominates(BasicBlock dom, BasicBlock node) { dom.dominates(node) }
|
||||
|
||||
/** Holds if `dom` post-dominates `node`. (This is reflexive.) */
|
||||
predicate bbPostDominates(BasicBlock dom, BasicBlock node) {
|
||||
bbStrictlyPostDominates(dom, node) or dom = node
|
||||
/**
|
||||
* DEPRECATED: Use `BasicBlock::strictlyPostDominates` instead.
|
||||
*
|
||||
* Holds if `dom` strictly post-dominates `node`.
|
||||
*/
|
||||
deprecated predicate bbStrictlyPostDominates(BasicBlock dom, BasicBlock node) {
|
||||
dom.strictlyPostDominates(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BasicBlock::postDominates` instead.
|
||||
*
|
||||
* Holds if `dom` post-dominates `node`. (This is reflexive.)
|
||||
*/
|
||||
deprecated predicate bbPostDominates(BasicBlock dom, BasicBlock node) { dom.postDominates(node) }
|
||||
|
||||
/**
|
||||
* The dominance frontier relation for basic blocks.
|
||||
*
|
||||
* This is equivalent to:
|
||||
*
|
||||
* ```
|
||||
* bbDominates(x, w.getABBPredecessor()) and not bbStrictlyDominates(x, w)
|
||||
* x.dominates(w.getAPredecessor()) and not x.strictlyDominates(w)
|
||||
* ```
|
||||
*/
|
||||
predicate dominanceFrontier(BasicBlock x, BasicBlock w) {
|
||||
x = w.getABBPredecessor() and not bbIDominates(x, w)
|
||||
x = w.getAPredecessor() and not x.immediatelyDominates(w)
|
||||
or
|
||||
exists(BasicBlock prev | dominanceFrontier(prev, w) |
|
||||
bbIDominates(x, prev) and
|
||||
not bbIDominates(x, w)
|
||||
x.immediatelyDominates(prev) and
|
||||
not x.immediatelyDominates(w)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(bb1, bb2)` is an edge that dominates `bb2`, that is, all other
|
||||
* predecessors of `bb2` are dominated by `bb2`. This implies that `bb1` is the
|
||||
* immediate dominator of `bb2`.
|
||||
*
|
||||
* This is a necessary and sufficient condition for an edge to dominate anything,
|
||||
* and in particular `dominatingEdge(bb1, bb2) and bb2.bbDominates(bb3)` means
|
||||
* that the edge `(bb1, bb2)` dominates `bb3`.
|
||||
*/
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
bbIDominates(bb1, bb2) and
|
||||
bb1.getABBSuccessor() = bb2 and
|
||||
forall(BasicBlock pred | pred = bb2.getABBPredecessor() and pred != bb1 | bbDominates(bb2, pred))
|
||||
}
|
||||
|
||||
/*
|
||||
* Predicates for expression-level dominance.
|
||||
*/
|
||||
@@ -102,7 +86,7 @@ predicate iDominates(ControlFlowNode dominator, ControlFlowNode node) {
|
||||
exists(BasicBlock bb, int i | dominator = bb.getNode(i) and node = bb.getNode(i + 1))
|
||||
or
|
||||
exists(BasicBlock dom, BasicBlock bb |
|
||||
bbIDominates(dom, bb) and
|
||||
dom.immediatelyDominates(bb) and
|
||||
dominator = dom.getLastNode() and
|
||||
node = bb.getFirstNode()
|
||||
)
|
||||
@@ -112,7 +96,7 @@ predicate iDominates(ControlFlowNode dominator, ControlFlowNode node) {
|
||||
pragma[inline]
|
||||
predicate strictlyDominates(ControlFlowNode dom, ControlFlowNode node) {
|
||||
// This predicate is gigantic, so it must be inlined.
|
||||
bbStrictlyDominates(dom.getBasicBlock(), node.getBasicBlock())
|
||||
dom.getBasicBlock().strictlyDominates(node.getBasicBlock())
|
||||
or
|
||||
exists(BasicBlock b, int i, int j | dom = b.getNode(i) and node = b.getNode(j) and i < j)
|
||||
}
|
||||
@@ -121,7 +105,7 @@ predicate strictlyDominates(ControlFlowNode dom, ControlFlowNode node) {
|
||||
pragma[inline]
|
||||
predicate dominates(ControlFlowNode dom, ControlFlowNode node) {
|
||||
// This predicate is gigantic, so it must be inlined.
|
||||
bbStrictlyDominates(dom.getBasicBlock(), node.getBasicBlock())
|
||||
dom.getBasicBlock().strictlyDominates(node.getBasicBlock())
|
||||
or
|
||||
exists(BasicBlock b, int i, int j | dom = b.getNode(i) and node = b.getNode(j) and i <= j)
|
||||
}
|
||||
@@ -130,7 +114,7 @@ predicate dominates(ControlFlowNode dom, ControlFlowNode node) {
|
||||
pragma[inline]
|
||||
predicate strictlyPostDominates(ControlFlowNode dom, ControlFlowNode node) {
|
||||
// This predicate is gigantic, so it must be inlined.
|
||||
bbStrictlyPostDominates(dom.getBasicBlock(), node.getBasicBlock())
|
||||
dom.getBasicBlock().strictlyPostDominates(node.getBasicBlock())
|
||||
or
|
||||
exists(BasicBlock b, int i, int j | dom = b.getNode(i) and node = b.getNode(j) and i > j)
|
||||
}
|
||||
@@ -139,7 +123,7 @@ predicate strictlyPostDominates(ControlFlowNode dom, ControlFlowNode node) {
|
||||
pragma[inline]
|
||||
predicate postDominates(ControlFlowNode dom, ControlFlowNode node) {
|
||||
// This predicate is gigantic, so it must be inlined.
|
||||
bbStrictlyPostDominates(dom.getBasicBlock(), node.getBasicBlock())
|
||||
dom.getBasicBlock().strictlyPostDominates(node.getBasicBlock())
|
||||
or
|
||||
exists(BasicBlock b, int i, int j | dom = b.getNode(i) and node = b.getNode(j) and i >= j)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class ConditionBlock extends BasicBlock {
|
||||
|
||||
/** Gets a `true`- or `false`-successor of the last node of this basic block. */
|
||||
BasicBlock getTestSuccessor(boolean testIsTrue) {
|
||||
result = this.getConditionNode().getABranchSuccessor(testIsTrue)
|
||||
result.getFirstNode() = this.getConditionNode().getABranchSuccessor(testIsTrue)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -68,7 +68,7 @@ class ConditionBlock extends BasicBlock {
|
||||
exists(BasicBlock succ |
|
||||
succ = this.getTestSuccessor(testIsTrue) and
|
||||
dominatingEdge(this, succ) and
|
||||
succ.bbDominates(controlled)
|
||||
succ.dominates(controlled)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -287,7 +287,7 @@ private predicate switchCaseControls(SwitchCase sc, BasicBlock bb) {
|
||||
// Pattern cases are handled as condition blocks
|
||||
not sc instanceof PatternCase and
|
||||
caseblock.getFirstNode() = sc.getControlFlowNode() and
|
||||
caseblock.bbDominates(bb) and
|
||||
caseblock.dominates(bb) and
|
||||
// Check we can't fall through from a previous block:
|
||||
forall(ControlFlowNode pred | pred = sc.getControlFlowNode().getAPredecessor() |
|
||||
isNonFallThroughPredecessor(sc, pred)
|
||||
@@ -300,14 +300,14 @@ private predicate preconditionBranchEdge(
|
||||
) {
|
||||
conditionCheckArgument(ma, _, branch) and
|
||||
bb1.getLastNode() = ma.getControlFlowNode() and
|
||||
bb2 = bb1.getLastNode().getANormalSuccessor()
|
||||
bb2.getFirstNode() = bb1.getLastNode().getANormalSuccessor()
|
||||
}
|
||||
|
||||
private predicate preconditionControls(MethodCall ma, BasicBlock controlled, boolean branch) {
|
||||
exists(BasicBlock check, BasicBlock succ |
|
||||
preconditionBranchEdge(ma, check, succ, branch) and
|
||||
dominatingEdge(check, succ) and
|
||||
succ.bbDominates(controlled)
|
||||
succ.dominates(controlled)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ private predicate callAlwaysPerformsAction(Call call, ActionConfiguration conf)
|
||||
private predicate actionDominatesExit(Callable callable, ActionConfiguration conf) {
|
||||
exists(ExitBlock exit |
|
||||
exit.getEnclosingCallable() = callable and
|
||||
actionBlock(conf).bbDominates(exit)
|
||||
actionBlock(conf).dominates(exit)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -56,12 +56,12 @@ private BasicBlock nonDominatingActionBlock(ActionConfiguration conf) {
|
||||
exists(ExitBlock exit |
|
||||
result = actionBlock(conf) and
|
||||
exit.getEnclosingCallable() = result.getEnclosingCallable() and
|
||||
not result.bbDominates(exit)
|
||||
not result.dominates(exit)
|
||||
)
|
||||
}
|
||||
|
||||
private class JoinBlock extends BasicBlock {
|
||||
JoinBlock() { 2 <= strictcount(this.getABBPredecessor()) }
|
||||
JoinBlock() { 2 <= strictcount(this.getAPredecessor()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,8 +72,8 @@ private predicate postActionBlock(BasicBlock bb, ActionConfiguration conf) {
|
||||
bb = nonDominatingActionBlock(conf)
|
||||
or
|
||||
if bb instanceof JoinBlock
|
||||
then forall(BasicBlock pred | pred = bb.getABBPredecessor() | postActionBlock(pred, conf))
|
||||
else postActionBlock(bb.getABBPredecessor(), conf)
|
||||
then forall(BasicBlock pred | pred = bb.getAPredecessor() | postActionBlock(pred, conf))
|
||||
else postActionBlock(bb.getAPredecessor(), conf)
|
||||
}
|
||||
|
||||
/** Holds if every path through `callable` goes through at least one action node. */
|
||||
|
||||
72
java/ql/lib/semmle/code/java/controlflow/SuccessorType.qll
Normal file
72
java/ql/lib/semmle/code/java/controlflow/SuccessorType.qll
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Provides different types of control flow successor types.
|
||||
*/
|
||||
|
||||
import java
|
||||
private import codeql.util.Boolean
|
||||
|
||||
private newtype TSuccessorType =
|
||||
TNormalSuccessor() or
|
||||
TBooleanSuccessor(Boolean branch) or
|
||||
TExceptionSuccessor()
|
||||
|
||||
/** The type of a control flow successor. */
|
||||
class SuccessorType extends TSuccessorType {
|
||||
/** Gets a textual representation of successor type. */
|
||||
string toString() { result = "SuccessorType" }
|
||||
}
|
||||
|
||||
/** A normal control flow successor. */
|
||||
class NormalSuccessor extends SuccessorType, TNormalSuccessor { }
|
||||
|
||||
/**
|
||||
* An exceptional control flow successor.
|
||||
*
|
||||
* This marks control flow edges that are taken when an exception is thrown.
|
||||
*/
|
||||
class ExceptionSuccessor extends SuccessorType, TExceptionSuccessor { }
|
||||
|
||||
/**
|
||||
* A conditional control flow successor.
|
||||
*
|
||||
* This currently only includes boolean successors (`BooleanSuccessor`).
|
||||
*/
|
||||
class ConditionalSuccessor extends SuccessorType, TBooleanSuccessor {
|
||||
/** Gets the Boolean value of this successor. */
|
||||
boolean getValue() { this = TBooleanSuccessor(result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Boolean control flow successor.
|
||||
*
|
||||
* For example, this program fragment:
|
||||
*
|
||||
* ```java
|
||||
* if (x < 0)
|
||||
* return 0;
|
||||
* else
|
||||
* return 1;
|
||||
* ```
|
||||
*
|
||||
* has a control flow graph containing Boolean successors:
|
||||
*
|
||||
* ```
|
||||
* if
|
||||
* |
|
||||
* x < 0
|
||||
* / \
|
||||
* / \
|
||||
* / \
|
||||
* true false
|
||||
* | \
|
||||
* return 0 return 1
|
||||
* ```
|
||||
*/
|
||||
class BooleanSuccessor = ConditionalSuccessor;
|
||||
|
||||
/**
|
||||
* A nullness control flow successor. This is currently unused for Java.
|
||||
*/
|
||||
class NullnessSuccessor extends ConditionalSuccessor {
|
||||
NullnessSuccessor() { none() }
|
||||
}
|
||||
@@ -209,7 +209,7 @@ class UnreachableBasicBlock extends BasicBlock {
|
||||
or
|
||||
// This block is not reachable in the CFG, and is not the entrypoint in a callable, an
|
||||
// expression in an assert statement, or a catch clause.
|
||||
forall(BasicBlock bb | bb = this.getABBPredecessor() | bb instanceof UnreachableBasicBlock) and
|
||||
forall(BasicBlock bb | bb = this.getAPredecessor() | bb instanceof UnreachableBasicBlock) and
|
||||
not exists(Callable c | c.getBody().getControlFlowNode() = this.getFirstNode()) and
|
||||
not this.getFirstNode().asExpr().getEnclosingStmt() instanceof AssertStmt and
|
||||
not this.getFirstNode().asStmt() instanceof CatchClause
|
||||
@@ -219,11 +219,10 @@ class UnreachableBasicBlock extends BasicBlock {
|
||||
// Not accessible from the switch expression
|
||||
unreachableCaseBlock = constSwitchStmt.getAFailingCase().getBasicBlock() and
|
||||
// Not accessible from the successful case
|
||||
not constSwitchStmt.getMatchingCase().getBasicBlock().getABBSuccessor*() =
|
||||
unreachableCaseBlock
|
||||
not constSwitchStmt.getMatchingCase().getBasicBlock().getASuccessor*() = unreachableCaseBlock
|
||||
|
|
||||
// Blocks dominated by an unreachable case block are unreachable
|
||||
unreachableCaseBlock.bbDominates(this)
|
||||
unreachableCaseBlock.dominates(this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ SsaVariable getADefinition(SsaVariable v, boolean fromBackEdge) {
|
||||
exists(SsaVariable inp, BasicBlock bb, boolean fbe |
|
||||
v.(SsaPhiNode).hasInputFromBlock(inp, bb) and
|
||||
result = getADefinition(inp, fbe) and
|
||||
(if v.getBasicBlock().bbDominates(bb) then fromBackEdge = true else fromBackEdge = fbe)
|
||||
(if v.getBasicBlock().dominates(bb) then fromBackEdge = true else fromBackEdge = fbe)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -290,10 +290,10 @@ private predicate guardImpliesEqual(Guard guard, boolean branch, SsaVariable v,
|
||||
)
|
||||
}
|
||||
|
||||
private ControlFlowNode getAGuardBranchSuccessor(Guard g, boolean branch) {
|
||||
result = g.(Expr).getControlFlowNode().(ConditionNode).getABranchSuccessor(branch)
|
||||
private BasicBlock getAGuardBranchSuccessor(Guard g, boolean branch) {
|
||||
result.getFirstNode() = g.(Expr).getControlFlowNode().(ConditionNode).getABranchSuccessor(branch)
|
||||
or
|
||||
result = g.(SwitchCase).getControlFlowNode() and branch = true
|
||||
result.getFirstNode() = g.(SwitchCase).getControlFlowNode() and branch = true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -306,7 +306,7 @@ private predicate guardControlsPhiBranch(
|
||||
guard.directlyControls(upd.getBasicBlock(), branch) and
|
||||
upd.getDefiningExpr().(VariableAssign).getSource() = e and
|
||||
upd = phi.getAPhiInput() and
|
||||
guard.getBasicBlock().bbStrictlyDominates(phi.getBasicBlock())
|
||||
guard.getBasicBlock().strictlyDominates(phi.getBasicBlock())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,7 +331,7 @@ private predicate conditionalAssign(SsaVariable v, Guard guard, boolean branch,
|
||||
forall(SsaVariable other | other != upd and other = phi.getAPhiInput() |
|
||||
guard.directlyControls(other.getBasicBlock(), branch.booleanNot())
|
||||
or
|
||||
other.getBasicBlock().bbDominates(guard.getBasicBlock()) and
|
||||
other.getBasicBlock().dominates(guard.getBasicBlock()) and
|
||||
not other.isLiveAtEndOfBlock(getAGuardBranchSuccessor(guard, branch))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -298,9 +298,9 @@ private predicate impossibleEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
private predicate leavingFinally(BasicBlock bb1, BasicBlock bb2, boolean normaledge) {
|
||||
exists(TryStmt try, BlockStmt finally |
|
||||
try.getFinally() = finally and
|
||||
bb1.getABBSuccessor() = bb2 and
|
||||
bb1.getEnclosingStmt().getEnclosingStmt*() = finally and
|
||||
not bb2.getEnclosingStmt().getEnclosingStmt*() = finally and
|
||||
bb1.getASuccessor() = bb2 and
|
||||
bb1.getFirstNode().getEnclosingStmt().getEnclosingStmt*() = finally and
|
||||
not bb2.getFirstNode().getEnclosingStmt().getEnclosingStmt*() = finally and
|
||||
if bb1.getLastNode().getANormalSuccessor() = bb2.getFirstNode()
|
||||
then normaledge = true
|
||||
else normaledge = false
|
||||
@@ -339,7 +339,7 @@ private predicate nullVarStep(
|
||||
midssa.isLiveAtEndOfBlock(mid) and
|
||||
not ensureNotNull(midssa).getBasicBlock() = mid and
|
||||
not assertFail(mid, _) and
|
||||
bb = mid.getABBSuccessor() and
|
||||
bb = mid.getASuccessor() and
|
||||
not impossibleEdge(mid, bb) and
|
||||
not exists(boolean branch | nullGuard(midssa, branch, false).hasBranchEdge(mid, bb, branch)) and
|
||||
not (leavingFinally(mid, bb, true) and midstoredcompletion = true) and
|
||||
|
||||
@@ -209,13 +209,13 @@ module Sem implements Semantic<Location> {
|
||||
|
||||
class BasicBlock = J::BasicBlock;
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
private predicate id(ExprParent x, ExprParent y) { x = y }
|
||||
|
||||
private predicate idOfAst(ExprParent x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
|
||||
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getAstNode(), y) }
|
||||
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getFirstNode().getAstNode(), y) }
|
||||
|
||||
int getBlockId1(BasicBlock bb) { idOf(bb, result) }
|
||||
|
||||
|
||||
@@ -321,14 +321,14 @@ private module Input implements TypeFlowInput<Location> {
|
||||
*/
|
||||
private predicate instanceofDisjunct(InstanceOfExpr ioe, BasicBlock bb, BaseSsaVariable v) {
|
||||
ioe.getExpr() = v.getAUse() and
|
||||
strictcount(bb.getABBPredecessor()) > 1 and
|
||||
strictcount(bb.getAPredecessor()) > 1 and
|
||||
exists(ConditionBlock cb | cb.getCondition() = ioe and cb.getTestSuccessor(true) = bb)
|
||||
}
|
||||
|
||||
/** Holds if `bb` is disjunctively guarded by multiple `instanceof` tests on `v`. */
|
||||
private predicate instanceofDisjunction(BasicBlock bb, BaseSsaVariable v) {
|
||||
strictcount(InstanceOfExpr ioe | instanceofDisjunct(ioe, bb, v)) =
|
||||
strictcount(bb.getABBPredecessor())
|
||||
strictcount(bb.getAPredecessor())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,7 +338,7 @@ private module Input implements TypeFlowInput<Location> {
|
||||
predicate instanceofDisjunctionGuarded(TypeFlowNode n, RefType t) {
|
||||
exists(BasicBlock bb, InstanceOfExpr ioe, BaseSsaVariable v, VarAccess va |
|
||||
instanceofDisjunction(bb, v) and
|
||||
bb.bbDominates(va.getBasicBlock()) and
|
||||
bb.dominates(va.getBasicBlock()) and
|
||||
va = v.getAUse() and
|
||||
instanceofDisjunct(ioe, bb, v) and
|
||||
t = ioe.getSyntacticCheckedType() and
|
||||
|
||||
@@ -145,7 +145,7 @@ private module BaseSsaImpl {
|
||||
/** Holds if `v` has an implicit definition at the entry, `b`, of the callable. */
|
||||
predicate hasEntryDef(BaseSsaSourceVariable v, BasicBlock b) {
|
||||
exists(LocalScopeVariable l, Callable c |
|
||||
v = TLocalVar(c, l) and c.getBody().getControlFlowNode() = b
|
||||
v = TLocalVar(c, l) and c.getBody().getBasicBlock() = b
|
||||
|
|
||||
l instanceof Parameter or
|
||||
l.getCallable() != c
|
||||
@@ -157,15 +157,14 @@ private import BaseSsaImpl
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
private import java as J
|
||||
private import semmle.code.java.controlflow.Dominance as Dom
|
||||
|
||||
class BasicBlock = J::BasicBlock;
|
||||
|
||||
class ControlFlowNode = J::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { Dom::bbIDominates(result, bb) }
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class SourceVariable = BaseSsaSourceVariable;
|
||||
|
||||
|
||||
@@ -83,12 +83,12 @@ private module CaptureInput implements VariableCapture::InputSig<Location> {
|
||||
|
||||
class ControlFlowNode = J::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { bbIDominates(result, bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) {
|
||||
result = bb.(J::BasicBlock).getABBSuccessor()
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result.(J::BasicBlock).immediatelyDominates(bb)
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.(J::BasicBlock).getASuccessor() }
|
||||
|
||||
//TODO: support capture of `this` in lambdas
|
||||
class CapturedVariable instanceof LocalScopeVariable {
|
||||
CapturedVariable() {
|
||||
|
||||
@@ -40,14 +40,14 @@ private module ThisFlow {
|
||||
|
||||
private int lastRank(BasicBlock b) { result = max(int rankix | thisRank(_, b, rankix)) }
|
||||
|
||||
private predicate blockPrecedesThisAccess(BasicBlock b) { thisAccess(_, b.getABBSuccessor*(), _) }
|
||||
private predicate blockPrecedesThisAccess(BasicBlock b) { thisAccess(_, b.getASuccessor*(), _) }
|
||||
|
||||
private predicate thisAccessBlockReaches(BasicBlock b1, BasicBlock b2) {
|
||||
thisAccess(_, b1, _) and b2 = b1.getABBSuccessor()
|
||||
thisAccess(_, b1, _) and b2 = b1.getASuccessor()
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
thisAccessBlockReaches(b1, mid) and
|
||||
b2 = mid.getABBSuccessor() and
|
||||
b2 = mid.getASuccessor() and
|
||||
not thisAccess(_, mid, _) and
|
||||
blockPrecedesThisAccess(b2)
|
||||
)
|
||||
|
||||
@@ -144,13 +144,13 @@ private predicate certainVariableUpdate(TrackedVar v, ControlFlowNode n, BasicBl
|
||||
pragma[nomagic]
|
||||
private predicate hasEntryDef(TrackedVar v, BasicBlock b) {
|
||||
exists(LocalScopeVariable l, Callable c |
|
||||
v = TLocalVar(c, l) and c.getBody().getControlFlowNode() = b
|
||||
v = TLocalVar(c, l) and c.getBody().getBasicBlock() = b
|
||||
|
|
||||
l instanceof Parameter or
|
||||
l.getCallable() != c
|
||||
)
|
||||
or
|
||||
v instanceof SsaSourceField and v.getEnclosingCallable().getBody().getControlFlowNode() = b
|
||||
v instanceof SsaSourceField and v.getEnclosingCallable().getBody().getBasicBlock() = b
|
||||
}
|
||||
|
||||
/** Holds if `n` might update the locally tracked variable `v`. */
|
||||
@@ -165,15 +165,14 @@ private predicate uncertainVariableUpdate(TrackedVar v, ControlFlowNode n, Basic
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
private import java as J
|
||||
private import semmle.code.java.controlflow.Dominance as Dom
|
||||
|
||||
class BasicBlock = J::BasicBlock;
|
||||
|
||||
class ControlFlowNode = J::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { Dom::bbIDominates(result, bb) }
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class SourceVariable = SsaSourceVariable;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ private predicate id(BB::ExprParent x, BB::ExprParent y) { x = y }
|
||||
|
||||
private predicate idOfAst(BB::ExprParent x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
|
||||
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getAstNode(), y) }
|
||||
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getFirstNode().getAstNode(), y) }
|
||||
|
||||
private int getId(BasicBlock bb) { idOf(bb, result) }
|
||||
|
||||
|
||||
@@ -24,6 +24,6 @@ private class SslProceedCall extends MethodCall {
|
||||
/** Holds if `m` trusts all certificates by calling `SslErrorHandler.proceed` unconditionally. */
|
||||
predicate trustsAllCerts(OnReceivedSslErrorMethod m) {
|
||||
exists(SslProceedCall pr | pr.getQualifier().(VarAccess).getVariable() = m.handlerArg() |
|
||||
pr.getBasicBlock().bbPostDominates(m.getBody().getBasicBlock())
|
||||
pr.getBasicBlock().postDominates(m.getBody().getBasicBlock())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ private module ValidationMethod<DataFlow::guardChecksSig/3 validationGuard> {
|
||||
validationMethod(ma.getMethod(), pos) and
|
||||
ma.getArgument(pos) = rv and
|
||||
adjacentUseUseSameVar(rv, result.asExpr()) and
|
||||
ma.getBasicBlock().bbDominates(result.asExpr().getBasicBlock())
|
||||
ma.getBasicBlock().dominates(result.asExpr().getBasicBlock())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ private class FullyDecodesUrlBarrier extends DataFlow::Node {
|
||||
exists(Variable v, Expr e | this.asExpr() = v.getAnAccess() |
|
||||
fullyDecodesUrlGuard(e) and
|
||||
e = v.getAnAccess() and
|
||||
e.getBasicBlock().bbDominates(this.asExpr().getBasicBlock())
|
||||
e.getBasicBlock().dominates(this.asExpr().getBasicBlock())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,16 +40,16 @@ private predicate validatedAccess(VarAccess va) {
|
||||
guardcall.getControlFlowNode() = node
|
||||
|
|
||||
exists(BasicBlock succ |
|
||||
succ = node.getANormalSuccessor() and
|
||||
succ.getFirstNode() = node.getANormalSuccessor() and
|
||||
dominatingEdge(node.getBasicBlock(), succ) and
|
||||
succ.bbDominates(va.getBasicBlock())
|
||||
succ.dominates(va.getBasicBlock())
|
||||
)
|
||||
or
|
||||
exists(BasicBlock bb, int i |
|
||||
bb.getNode(i) = node and
|
||||
bb.getNode(i + 1) = node.getANormalSuccessor()
|
||||
|
|
||||
bb.bbStrictlyDominates(va.getBasicBlock()) or
|
||||
bb.strictlyDominates(va.getBasicBlock()) or
|
||||
bb.getNode(any(int j | j > i)).asExpr() = va
|
||||
)
|
||||
)
|
||||
|
||||
@@ -99,8 +99,8 @@ predicate failedLock(LockType t, BasicBlock lockblock, BasicBlock exblock) {
|
||||
)
|
||||
) and
|
||||
(
|
||||
lock.getAnExceptionSuccessor() = exblock or
|
||||
lock.(ConditionNode).getAFalseSuccessor() = exblock
|
||||
lock.getAnExceptionSuccessor() = exblock.getFirstNode() or
|
||||
lock.(ConditionNode).getAFalseSuccessor() = exblock.getFirstNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -113,7 +113,7 @@ predicate heldByCurrentThreadCheck(LockType t, BasicBlock checkblock, BasicBlock
|
||||
exists(ConditionBlock conditionBlock |
|
||||
conditionBlock.getCondition() = t.getIsHeldByCurrentThreadAccess()
|
||||
|
|
||||
conditionBlock.getBasicBlock() = checkblock and
|
||||
conditionBlock = checkblock and
|
||||
conditionBlock.getTestSuccessor(false) = falsesucc
|
||||
)
|
||||
}
|
||||
@@ -133,7 +133,7 @@ predicate variableLockStateCheck(LockType t, BasicBlock checkblock, BasicBlock f
|
||||
conditionBlock.getTestSuccessor(true) = t.getUnlockAccess().getBasicBlock() and
|
||||
conditionBlock.getCondition() = v
|
||||
|
|
||||
conditionBlock.getBasicBlock() = checkblock and
|
||||
conditionBlock = checkblock and
|
||||
conditionBlock.getTestSuccessor(false) = falsesucc
|
||||
)
|
||||
}
|
||||
@@ -145,9 +145,7 @@ predicate variableLockStateCheck(LockType t, BasicBlock checkblock, BasicBlock f
|
||||
predicate blockIsLocked(LockType t, BasicBlock src, BasicBlock b, int locks) {
|
||||
lockUnlockBlock(t, b, locks) and src = b and locks > 0
|
||||
or
|
||||
exists(BasicBlock pred, int predlocks, int curlocks, int failedlock |
|
||||
pred = b.getABBPredecessor()
|
||||
|
|
||||
exists(BasicBlock pred, int predlocks, int curlocks, int failedlock | pred = b.getAPredecessor() |
|
||||
// The number of net locks from the `src` block to the predecessor block `pred` is `predlocks`.
|
||||
blockIsLocked(t, src, pred, predlocks) and
|
||||
// The recursive call ensures that at least one lock is held, so do not consider the false
|
||||
|
||||
@@ -18,6 +18,6 @@ where
|
||||
iteration = inner.getAnIterationVariable() and
|
||||
iteration = outer.getAnIterationVariable() and
|
||||
inner.getEnclosingStmt+() = outer and
|
||||
inner.getBasicBlock().getABBSuccessor+() = outer.getCondition().getBasicBlock()
|
||||
inner.getBasicBlock().getASuccessor+() = outer.getCondition().getBasicBlock()
|
||||
select inner.getCondition(), "Nested for statement uses loop variable $@ of enclosing $@.",
|
||||
iteration, iteration.getName(), outer, "for statement"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.8
|
||||
* @precision medium
|
||||
* @precision low
|
||||
* @id java/hardcoded-credential-api-call
|
||||
* @tags security
|
||||
* external/cwe/cwe-798
|
||||
|
||||
@@ -37,7 +37,7 @@ predicate overwritten(VariableUpdate upd) {
|
||||
bb1.getNode(i) = upd.getControlFlowNode() and
|
||||
bb2.getNode(j) = overwrite.getControlFlowNode()
|
||||
|
|
||||
bb1.getABBSuccessor+() = bb2
|
||||
bb1.getASuccessor+() = bb2
|
||||
or
|
||||
bb1 = bb2 and i < j
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ private predicate blockInSwitch(SwitchStmt s, BasicBlock b) {
|
||||
|
||||
private predicate switchCaseControlFlow(SwitchStmt switch, BasicBlock b1, BasicBlock b2) {
|
||||
blockInSwitch(switch, b1) and
|
||||
b1.getABBSuccessor() = b2 and
|
||||
b1.getASuccessor() = b2 and
|
||||
blockInSwitch(switch, b2)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `java/hardcoded-credential-api-call` has been removed from all query suites.
|
||||
@@ -13,7 +13,7 @@ import semmle.code.java.dataflow.SSA
|
||||
|
||||
class SsaConvertibleReadAccess extends VarRead {
|
||||
SsaConvertibleReadAccess() {
|
||||
this.getEnclosingCallable().getBody().getBasicBlock().getABBSuccessor*() = this.getBasicBlock() and
|
||||
this.getEnclosingCallable().getBody().getBasicBlock().getASuccessor*() = this.getBasicBlock() and
|
||||
(
|
||||
not exists(this.getQualifier())
|
||||
or
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import default
|
||||
import java
|
||||
import semmle.code.java.controlflow.Dominance
|
||||
|
||||
from BasicBlock b, BasicBlock b2
|
||||
where bbStrictlyDominates(b, b2)
|
||||
where b.strictlyDominates(b2)
|
||||
select b, b2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import default
|
||||
import java
|
||||
|
||||
from BasicBlock b, BasicBlock b2
|
||||
where b.getABBSuccessor() = b2
|
||||
where b.getASuccessor() = b2
|
||||
select b, b2
|
||||
|
||||
@@ -16,6 +16,6 @@ predicate dominanceCounterExample(ControlFlowNode entry, ControlFlowNode dom, Co
|
||||
|
||||
from Callable c, ControlFlowNode dom, ControlFlowNode node
|
||||
where
|
||||
(strictlyDominates(dom, node) or bbStrictlyDominates(dom, node)) and
|
||||
strictlyDominates(dom, node) and
|
||||
dominanceCounterExample(c.getBody().getControlFlowNode(), dom, node)
|
||||
select c, dom, node
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import default
|
||||
import java
|
||||
import semmle.code.java.controlflow.Dominance
|
||||
|
||||
from BasicBlock b, BasicBlock b2
|
||||
where bbStrictlyDominates(b, b2)
|
||||
where b.strictlyDominates(b2)
|
||||
select b, b2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import default
|
||||
import java
|
||||
|
||||
from BasicBlock b, BasicBlock b2
|
||||
where b.getABBSuccessor() = b2
|
||||
where b.getASuccessor() = b2
|
||||
select b, b2
|
||||
|
||||
@@ -16,6 +16,6 @@ predicate dominanceCounterExample(ControlFlowNode entry, ControlFlowNode dom, Co
|
||||
|
||||
from Callable c, ControlFlowNode dom, ControlFlowNode node
|
||||
where
|
||||
(strictlyDominates(dom, node) or bbStrictlyDominates(dom, node)) and
|
||||
strictlyDominates(dom, node) and
|
||||
dominanceCounterExample(c.getBody().getControlFlowNode(), dom, node)
|
||||
select c, dom, node
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import default
|
||||
import java
|
||||
import semmle.code.java.controlflow.Dominance
|
||||
|
||||
from BasicBlock b, BasicBlock b2
|
||||
where bbStrictlyDominates(b, b2)
|
||||
where b.strictlyDominates(b2)
|
||||
select b, b2
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user