mirror of
https://github.com/github/codeql.git
synced 2025-12-16 08:43:11 +01:00
Merge branch 'main' into redsun82/rust-item-reorg
This commit is contained in:
4
.github/copilot-instructions.md
vendored
Normal file
4
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
When reviewing code:
|
||||
* do not review changes in files with `.expected` extension (they are automatically ensured to be correct).
|
||||
* in `.ql` and `.qll` files, do not try to review the code itself as you don't understand the programming language
|
||||
well enough to make comments in these languages. You can still check for typos or comment improvements.
|
||||
23
.github/workflows/check-overlay-annotations.yml
vendored
Normal file
23
.github/workflows/check-overlay-annotations.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Check overlay annotations
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'rc/*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- 'rc/*'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check overlay annotations
|
||||
run: python config/add-overlay-annotations.py --check java
|
||||
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
- name: Create database
|
||||
run: |
|
||||
"${CODEQL}" database create \
|
||||
--search-path "${{ github.workspace }}"
|
||||
--search-path "${{ github.workspace }}" \
|
||||
--threads 4 \
|
||||
--language ql --source-root "${{ github.workspace }}/repo" \
|
||||
"${{ runner.temp }}/database"
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
class Accessible extends @accessible {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Container extends @container {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Initialiser extends @initialiser {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Stmt extends @stmt {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isLocationDefault(Location l) {
|
||||
diagnostics(_, _, _, _, _, l)
|
||||
or
|
||||
macroinvocations(_, _, l, _)
|
||||
or
|
||||
fun_decls(_, _, _, _, l)
|
||||
or
|
||||
var_decls(_, _, _, _, l)
|
||||
or
|
||||
type_decls(_, _, l)
|
||||
or
|
||||
namespace_decls(_, _, l, _)
|
||||
or
|
||||
namespace_decls(_, _, _, l)
|
||||
or
|
||||
usings(_, _, l, _)
|
||||
or
|
||||
static_asserts(_, _, _, l, _)
|
||||
or
|
||||
enumconstants(_, _, _, _, _, l)
|
||||
or
|
||||
concept_templates(_, _, l)
|
||||
or
|
||||
attributes(_, _, _, _, l)
|
||||
or
|
||||
attribute_args(_, _, _, _, l)
|
||||
or
|
||||
derivations(_, _, _, _, l)
|
||||
or
|
||||
frienddecls(_, _, _, l)
|
||||
or
|
||||
comments(_, _, l)
|
||||
or
|
||||
namequalifiers(_, _, _, l)
|
||||
or
|
||||
lambda_capture(_, _, _, _, _, _, l)
|
||||
or
|
||||
preprocdirects(_, _, l)
|
||||
or
|
||||
xmllocations(_, l)
|
||||
or
|
||||
locations_default(l, _, 0, 0, 0, 0) // For containers.
|
||||
}
|
||||
|
||||
predicate isLocationExpr(Location l) {
|
||||
initialisers(_, _, _, l)
|
||||
or
|
||||
exprs(_, _, l)
|
||||
}
|
||||
|
||||
predicate isLocationStmt(Location l) { stmts(_, _, l) }
|
||||
|
||||
newtype TExprOrStmtLocation =
|
||||
TExprLocation(Location l, Container c, int startLine, int startColumn, int endLine, int endColumn) {
|
||||
isLocationExpr(l) and
|
||||
(isLocationDefault(l) or isLocationStmt(l)) and
|
||||
locations_default(l, c, startLine, startColumn, endLine, endColumn)
|
||||
} or
|
||||
TStmtLocation(Location l, Container c, int startLine, int startColumn, int endLine, int endColumn) {
|
||||
isLocationStmt(l) and
|
||||
(isLocationDefault(l) or isLocationExpr(l)) and
|
||||
locations_default(l, c, startLine, startColumn, endLine, endColumn)
|
||||
}
|
||||
|
||||
module Fresh = QlBuiltins::NewEntity<TExprOrStmtLocation>;
|
||||
|
||||
class NewLocationBase = @location_default or Fresh::EntityId;
|
||||
|
||||
class NewLocation extends NewLocationBase {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
query predicate new_locations_default(
|
||||
NewLocation l, Container c, int startLine, int startColumn, int endLine, int endColumn
|
||||
) {
|
||||
isLocationDefault(l) and
|
||||
locations_default(l, c, startLine, startColumn, endLine, endColumn)
|
||||
}
|
||||
|
||||
query predicate new_locations_expr(
|
||||
NewLocation l, Container c, int startLine, int startColumn, int endLine, int endColumn
|
||||
) {
|
||||
exists(Location l_old |
|
||||
isLocationExpr(l_old) and
|
||||
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
||||
|
|
||||
if not isLocationDefault(l_old) and not isLocationStmt(l)
|
||||
then l = l_old
|
||||
else l = Fresh::map(TExprLocation(l_old, c, startLine, startColumn, endLine, endColumn))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate new_locations_stmt(
|
||||
NewLocation l, Container c, int startLine, int startColumn, int endLine, int endColumn
|
||||
) {
|
||||
exists(Location l_old |
|
||||
isLocationStmt(l_old) and
|
||||
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
||||
|
|
||||
if not isLocationDefault(l_old) and not isLocationExpr(l)
|
||||
then l = l_old
|
||||
else l = Fresh::map(TStmtLocation(l_old, c, startLine, startColumn, endLine, endColumn))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate new_exprs(Expr e, int kind, NewLocation l) {
|
||||
exists(Location l_old, Container c, int startLine, int startColumn, int endLine, int endColumn |
|
||||
exprs(e, kind, l_old) and
|
||||
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
||||
|
|
||||
if not isLocationDefault(l_old) and not isLocationStmt(l)
|
||||
then l = l_old
|
||||
else l = Fresh::map(TExprLocation(l_old, c, startLine, startColumn, endLine, endColumn))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate new_initialisers(Initialiser i, Accessible v, Expr e, NewLocation l) {
|
||||
exists(Location l_old, Container c, int startLine, int startColumn, int endLine, int endColumn |
|
||||
initialisers(i, v, e, l_old) and
|
||||
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
||||
|
|
||||
if not isLocationDefault(l_old) and not isLocationStmt(l)
|
||||
then l = l_old
|
||||
else l = Fresh::map(TExprLocation(l_old, c, startLine, startColumn, endLine, endColumn))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate new_stmts(Stmt s, int kind, NewLocation l) {
|
||||
exists(Location l_old, Container c, int startLine, int startColumn, int endLine, int endColumn |
|
||||
stmts(s, kind, l_old) and
|
||||
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
||||
|
|
||||
if not isLocationDefault(l_old) and not isLocationExpr(l)
|
||||
then l = l_old
|
||||
else l = Fresh::map(TStmtLocation(l_old, c, startLine, startColumn, endLine, endColumn))
|
||||
)
|
||||
}
|
||||
2475
cpp/downgrades/e70d0b653187b93d9688f21c9db46bb1cd46ab78/old.dbscheme
Normal file
2475
cpp/downgrades/e70d0b653187b93d9688f21c9db46bb1cd46ab78/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
description: Merge location tables
|
||||
compatibility: partial
|
||||
locations_default.rel: run downgrades.ql new_locations_default
|
||||
locations_expr.rel: run downgrades.ql new_locations_expr
|
||||
locations_stmt.rel: run downgrades.ql new_locations_stmt
|
||||
exprs.rel: run downgrades.ql new_exprs
|
||||
initialisers.rel: run downgrades.ql new_initialisers
|
||||
stmts.rel: run downgrades.ql new_stmts
|
||||
4
cpp/ql/lib/change-notes/2025-06-20-oracle-oci-models.md
Normal file
4
cpp/ql/lib/change-notes/2025-06-20-oracle-oci-models.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added `sql-injection` sink models for the Oracle Call Interface (OCI) database library functions `OCIStmtPrepare` and `OCIStmtPrepare2`.
|
||||
4
cpp/ql/lib/change-notes/2025-06-27-locations.md
Normal file
4
cpp/ql/lib/change-notes/2025-06-27-locations.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `UnknownDefaultLocation`, `UnknownExprLocation`, and `UnknownStmtLocation` classes have been deprecated. Use `UnknownLocation` instead.
|
||||
@@ -8,7 +8,7 @@ module CryptoInput implements InputSig<Language::Location> {
|
||||
|
||||
class LocatableElement = Language::Locatable;
|
||||
|
||||
class UnknownLocation = Language::UnknownDefaultLocation;
|
||||
class UnknownLocation = Language::UnknownLocation;
|
||||
|
||||
LocatableElement dfn_to_element(DataFlow::Node node) {
|
||||
result = node.asExpr() or
|
||||
@@ -56,7 +56,7 @@ module ArtifactFlowConfig implements DataFlow::ConfigSig {
|
||||
module ArtifactFlow = DataFlow::Global<ArtifactFlowConfig>;
|
||||
|
||||
/**
|
||||
* Artifact output to node input configuration
|
||||
* An artifact output to node input configuration
|
||||
*/
|
||||
abstract class AdditionalFlowInputStep extends DataFlow::Node {
|
||||
abstract DataFlow::Node getOutput();
|
||||
@@ -91,9 +91,8 @@ module GenericDataSourceFlowConfig implements DataFlow::ConfigSig {
|
||||
|
||||
module GenericDataSourceFlow = TaintTracking::Global<GenericDataSourceFlowConfig>;
|
||||
|
||||
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof Literal {
|
||||
ConstantDataSource() { this instanceof OpenSslGenericSourceCandidateLiteral }
|
||||
|
||||
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof OpenSslGenericSourceCandidateLiteral
|
||||
{
|
||||
override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
|
||||
@@ -48,7 +48,7 @@ module KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::
|
||||
module KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow =
|
||||
DataFlow::Global<KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig>;
|
||||
|
||||
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof OpenSslPaddingLiteral }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
@@ -60,8 +60,8 @@ module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataF
|
||||
}
|
||||
}
|
||||
|
||||
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
|
||||
DataFlow::Global<RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
|
||||
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
|
||||
DataFlow::Global<RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
|
||||
|
||||
class OpenSslAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep {
|
||||
OpenSslAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) }
|
||||
@@ -114,11 +114,11 @@ class CopyAndDupAlgorithmPassthroughCall extends AlgorithmPassthroughCall {
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class NIDToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
class NidToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
NIDToPointerPassthroughCall() {
|
||||
NidToPointerPassthroughCall() {
|
||||
this.getTarget().getName() in ["OBJ_nid2obj", "OBJ_nid2ln", "OBJ_nid2sn"] and
|
||||
inNode.asExpr() = this.getArgument(0) and
|
||||
outNode.asExpr() = this
|
||||
@@ -150,11 +150,11 @@ class PointerToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class PointerToNIDPassthroughCall extends AlgorithmPassthroughCall {
|
||||
class PointerToNidPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
PointerToNIDPassthroughCall() {
|
||||
PointerToNidPassthroughCall() {
|
||||
this.getTarget().getName() in ["OBJ_obj2nid", "OBJ_ln2nid", "OBJ_sn2nid", "OBJ_txt2nid"] and
|
||||
(
|
||||
inNode.asIndirectExpr() = this.getArgument(0)
|
||||
|
||||
@@ -5,36 +5,35 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import AlgToAVCFlow
|
||||
private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as KeyOpAlg
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSslBlockModeAlgorithmExpr`, converts this to a block family type.
|
||||
* Does not bind if there is no mapping (no mapping to 'unknown' or 'other').
|
||||
*/
|
||||
predicate knownOpenSslConstantToBlockModeFamilyType(
|
||||
KnownOpenSslBlockModeAlgorithmExpr e, Crypto::TBlockCipherModeOfOperationType type
|
||||
KnownOpenSslBlockModeAlgorithmExpr e, KeyOpAlg::ModeOfOperationType type
|
||||
) {
|
||||
exists(string name |
|
||||
name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
|
||||
(
|
||||
name.matches("CBC") and type instanceof Crypto::CBC
|
||||
name = "CBC" and type instanceof KeyOpAlg::CBC
|
||||
or
|
||||
name.matches("CFB%") and type instanceof Crypto::CFB
|
||||
name = "CFB%" and type instanceof KeyOpAlg::CFB
|
||||
or
|
||||
name.matches("CTR") and type instanceof Crypto::CTR
|
||||
name = "CTR" and type instanceof KeyOpAlg::CTR
|
||||
or
|
||||
name.matches("GCM") and type instanceof Crypto::GCM
|
||||
name = "GCM" and type instanceof KeyOpAlg::GCM
|
||||
or
|
||||
name.matches("OFB") and type instanceof Crypto::OFB
|
||||
name = "OFB" and type instanceof KeyOpAlg::OFB
|
||||
or
|
||||
name.matches("XTS") and type instanceof Crypto::XTS
|
||||
name = "XTS" and type instanceof KeyOpAlg::XTS
|
||||
or
|
||||
name.matches("CCM") and type instanceof Crypto::CCM
|
||||
name = "CCM" and type instanceof KeyOpAlg::CCM
|
||||
or
|
||||
name.matches("GCM") and type instanceof Crypto::GCM
|
||||
name = "CCM" and type instanceof KeyOpAlg::CCM
|
||||
or
|
||||
name.matches("CCM") and type instanceof Crypto::CCM
|
||||
or
|
||||
name.matches("ECB") and type instanceof Crypto::ECB
|
||||
name = "ECB" and type instanceof KeyOpAlg::ECB
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -64,10 +63,10 @@ class KnownOpenSslBlockModeConstantAlgorithmInstance extends OpenSslAlgorithmIns
|
||||
getterCall = this
|
||||
}
|
||||
|
||||
override Crypto::TBlockCipherModeOfOperationType getModeType() {
|
||||
override KeyOpAlg::ModeOfOperationType getModeType() {
|
||||
knownOpenSslConstantToBlockModeFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSslConstantToBlockModeFamilyType(this, _) and result = Crypto::OtherMode()
|
||||
not knownOpenSslConstantToBlockModeFamilyType(this, _) and result = KeyOpAlg::OtherMode()
|
||||
}
|
||||
|
||||
// NOTE: I'm not going to attempt to parse out the mode specific part, so returning
|
||||
|
||||
@@ -33,9 +33,9 @@ predicate knownOpenSslConstantToCipherFamilyType(
|
||||
or
|
||||
name.matches("CAST5%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::CAST5())
|
||||
or
|
||||
name.matches("2DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DoubleDES())
|
||||
name.matches("2DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DOUBLE_DES())
|
||||
or
|
||||
name.matches("3DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TripleDES())
|
||||
name.matches("3DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TRIPLE_DES())
|
||||
or
|
||||
name.matches("DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DES())
|
||||
or
|
||||
@@ -113,7 +113,7 @@ class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstan
|
||||
this.(KnownOpenSslCipherAlgorithmExpr).getExplicitKeySize() = result
|
||||
}
|
||||
|
||||
override Crypto::KeyOpAlg::Algorithm getAlgorithmType() {
|
||||
override KeyOpAlg::AlgorithmType getAlgorithmType() {
|
||||
knownOpenSslConstantToCipherFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSslConstantToCipherFamilyType(this, _) and
|
||||
|
||||
@@ -39,8 +39,14 @@ class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorith
|
||||
result = this.(Call).getTarget().getName()
|
||||
}
|
||||
|
||||
override Crypto::TEllipticCurveType getEllipticCurveType() {
|
||||
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _, result)
|
||||
override Crypto::EllipticCurveFamilyType getEllipticCurveFamilyType() {
|
||||
if
|
||||
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
|
||||
_)
|
||||
then
|
||||
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
|
||||
result)
|
||||
else result = Crypto::OtherEllipticCurveType()
|
||||
}
|
||||
|
||||
override string getParsedEllipticCurveName() {
|
||||
@@ -48,7 +54,7 @@ class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorith
|
||||
}
|
||||
|
||||
override int getKeySize() {
|
||||
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.(KnownOpenSslAlgorithmExpr)
|
||||
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.(KnownOpenSslAlgorithmExpr)
|
||||
.getNormalizedName(), result, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,21 +11,21 @@ predicate knownOpenSslConstantToHashFamilyType(
|
||||
exists(string name |
|
||||
name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
|
||||
(
|
||||
name.matches("BLAKE2B") and type instanceof Crypto::BLAKE2B
|
||||
name = "BLAKE2B" and type instanceof Crypto::BLAKE2B
|
||||
or
|
||||
name.matches("BLAKE2S") and type instanceof Crypto::BLAKE2S
|
||||
name = "BLAKE2S" and type instanceof Crypto::BLAKE2S
|
||||
or
|
||||
name.matches("GOST%") and type instanceof Crypto::GOSTHash
|
||||
name.matches("GOST%") and type instanceof Crypto::GOST_HASH
|
||||
or
|
||||
name.matches("MD2") and type instanceof Crypto::MD2
|
||||
name = "MD2" and type instanceof Crypto::MD2
|
||||
or
|
||||
name.matches("MD4") and type instanceof Crypto::MD4
|
||||
name = "MD4" and type instanceof Crypto::MD4
|
||||
or
|
||||
name.matches("MD5") and type instanceof Crypto::MD5
|
||||
name = "MD5" and type instanceof Crypto::MD5
|
||||
or
|
||||
name.matches("MDC2") and type instanceof Crypto::MDC2
|
||||
name = "MDC2" and type instanceof Crypto::MDC2
|
||||
or
|
||||
name.matches("POLY1305") and type instanceof Crypto::POLY1305
|
||||
name = "POLY1305" and type instanceof Crypto::POLY1305
|
||||
or
|
||||
name.matches(["SHA", "SHA1"]) and type instanceof Crypto::SHA1
|
||||
or
|
||||
@@ -33,13 +33,13 @@ predicate knownOpenSslConstantToHashFamilyType(
|
||||
or
|
||||
name.matches("SHA3-%") and type instanceof Crypto::SHA3
|
||||
or
|
||||
name.matches(["SHAKE"]) and type instanceof Crypto::SHAKE
|
||||
name = "SHAKE" and type instanceof Crypto::SHAKE
|
||||
or
|
||||
name.matches("SM3") and type instanceof Crypto::SM3
|
||||
name = "SM3" and type instanceof Crypto::SM3
|
||||
or
|
||||
name.matches("RIPEMD160") and type instanceof Crypto::RIPEMD160
|
||||
name = "RIPEMD160" and type instanceof Crypto::RIPEMD160
|
||||
or
|
||||
name.matches("WHIRLPOOL") and type instanceof Crypto::WHIRLPOOL
|
||||
name = "WHIRLPOOL" and type instanceof Crypto::WHIRLPOOL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -210,7 +210,8 @@ string getAlgorithmAlias(string alias) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds aliases of known alagorithms defined by users (through obj_name_add and various macros pointing to this function)
|
||||
* Holds for aliases of known algorithms defined by users
|
||||
* (through obj_name_add and various macros pointing to this function).
|
||||
*
|
||||
* The `target` and `alias` are converted to lowercase to be of a standard form.
|
||||
*/
|
||||
@@ -222,7 +223,7 @@ predicate customAliases(string target, string alias) {
|
||||
}
|
||||
|
||||
/**
|
||||
* A hard-coded mapping of known algorithm aliases in OpenSsl.
|
||||
* Holds for a hard-coded mapping of known algorithm aliases in OpenSsl.
|
||||
* This was derived by applying the same kind of logic foun din `customAliases` to the
|
||||
* OpenSsl code base directly.
|
||||
*
|
||||
|
||||
@@ -7,7 +7,7 @@ private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
||||
private import AlgToAVCFlow
|
||||
|
||||
class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::MACAlgorithmInstance instanceof KnownOpenSslMacAlgorithmExpr
|
||||
Crypto::MacAlgorithmInstance instanceof KnownOpenSslMacAlgorithmExpr
|
||||
{
|
||||
OpenSslAlgorithmValueConsumer getterCall;
|
||||
|
||||
@@ -39,14 +39,14 @@ class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
result = this.(Call).getTarget().getName()
|
||||
}
|
||||
|
||||
override Crypto::TMACType getMacType() {
|
||||
this instanceof KnownOpenSslHMacAlgorithmExpr and result instanceof Crypto::THMAC
|
||||
override Crypto::MacType getMacType() {
|
||||
this instanceof KnownOpenSslHMacAlgorithmExpr and result = Crypto::HMAC()
|
||||
or
|
||||
this instanceof KnownOpenSslCMacAlgorithmExpr and result instanceof Crypto::TCMAC
|
||||
this instanceof KnownOpenSslCMacAlgorithmExpr and result = Crypto::CMAC()
|
||||
}
|
||||
}
|
||||
|
||||
class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HMACAlgorithmInstance,
|
||||
class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HmacAlgorithmInstance,
|
||||
KnownOpenSslMacConstantAlgorithmInstance
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||
@@ -54,13 +54,15 @@ class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HMACAlgorithmIns
|
||||
then
|
||||
// ASSUMPTION: if there is an explicit hash algorithm, it is already modeled
|
||||
// and we can simply grab that model's AVC
|
||||
exists(OpenSslAlgorithmInstance inst | inst.getAvc() = result and inst = this)
|
||||
this.(OpenSslAlgorithmInstance).getAvc() = result
|
||||
else
|
||||
// ASSUMPTION: If no explicit algorithm is given, then it is assumed to be configured by
|
||||
// a signature operation
|
||||
exists(Crypto::SignatureOperationInstance s |
|
||||
s.getHashAlgorithmValueConsumer() = result and
|
||||
s.getAnAlgorithmValueConsumer() = this.getAvc()
|
||||
// ASSUMPTION: If no explicit algorithm is given, then find
|
||||
// where the current AVC traces to a HashAlgorithmIO consuming operation step.
|
||||
// TODO: need to consider getting reset values, tracing down to the first set for now
|
||||
exists(OperationStep s, AvcContextCreationStep avc |
|
||||
avc = this.getAvc() and
|
||||
avc.flowsToOperationStep(s) and
|
||||
s.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import AlgToAVCFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as KeyOpAlg
|
||||
|
||||
/**
|
||||
* A class to define padding specific integer values.
|
||||
@@ -28,18 +29,18 @@ class OpenSslPaddingLiteral extends Literal {
|
||||
* Does not bind if there is no mapping (no mapping to 'unknown' or 'other').
|
||||
*/
|
||||
predicate knownOpenSslConstantToPaddingFamilyType(
|
||||
KnownOpenSslPaddingAlgorithmExpr e, Crypto::TPaddingType type
|
||||
KnownOpenSslPaddingAlgorithmExpr e, KeyOpAlg::PaddingSchemeType type
|
||||
) {
|
||||
exists(string name |
|
||||
name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
|
||||
(
|
||||
name.matches("OAEP") and type = Crypto::OAEP()
|
||||
name = "OAEP" and type = KeyOpAlg::OAEP()
|
||||
or
|
||||
name.matches("PSS") and type = Crypto::PSS()
|
||||
name = "PSS" and type = KeyOpAlg::PSS()
|
||||
or
|
||||
name.matches("PKCS7") and type = Crypto::PKCS7()
|
||||
name = "PKCS7" and type = KeyOpAlg::PKCS7()
|
||||
or
|
||||
name.matches("PKCS1V15") and type = Crypto::PKCS1_v1_5()
|
||||
name = "PKCS1V15" and type = KeyOpAlg::PKCS1_V1_5()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -85,7 +86,7 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a padding-specific consumer
|
||||
RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
) and
|
||||
isPaddingSpecificConsumer = true
|
||||
}
|
||||
@@ -98,24 +99,24 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
|
||||
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
|
||||
|
||||
Crypto::TPaddingType getKnownPaddingType() {
|
||||
this.(Literal).getValue().toInt() in [1, 7, 8] and result = Crypto::PKCS1_v1_5()
|
||||
KeyOpAlg::PaddingSchemeType getKnownPaddingType() {
|
||||
this.(Literal).getValue().toInt() in [1, 7, 8] and result = KeyOpAlg::PKCS1_V1_5()
|
||||
or
|
||||
this.(Literal).getValue().toInt() = 3 and result = Crypto::NoPadding()
|
||||
this.(Literal).getValue().toInt() = 3 and result = KeyOpAlg::NoPadding()
|
||||
or
|
||||
this.(Literal).getValue().toInt() = 4 and result = Crypto::OAEP()
|
||||
this.(Literal).getValue().toInt() = 4 and result = KeyOpAlg::OAEP()
|
||||
or
|
||||
this.(Literal).getValue().toInt() = 5 and result = Crypto::ANSI_X9_23()
|
||||
this.(Literal).getValue().toInt() = 5 and result = KeyOpAlg::ANSI_X9_23()
|
||||
or
|
||||
this.(Literal).getValue().toInt() = 6 and result = Crypto::PSS()
|
||||
this.(Literal).getValue().toInt() = 6 and result = KeyOpAlg::PSS()
|
||||
}
|
||||
|
||||
override Crypto::TPaddingType getPaddingType() {
|
||||
override KeyOpAlg::PaddingSchemeType getPaddingType() {
|
||||
isPaddingSpecificConsumer = true and
|
||||
(
|
||||
result = this.getKnownPaddingType()
|
||||
or
|
||||
not exists(this.getKnownPaddingType()) and result = Crypto::OtherPadding()
|
||||
not exists(this.getKnownPaddingType()) and result = KeyOpAlg::OtherPadding()
|
||||
)
|
||||
or
|
||||
isPaddingSpecificConsumer = false and
|
||||
@@ -143,7 +144,7 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
// this instanceof Literal and
|
||||
// this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8]
|
||||
// // TODO: trace to padding-specific consumers
|
||||
// RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
|
||||
// RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
|
||||
// }
|
||||
// override string getRawPaddingAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
// override Crypto::TPaddingType getPaddingType() {
|
||||
@@ -161,18 +162,18 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
|
||||
// else result = Crypto::OtherPadding()
|
||||
// }
|
||||
// }
|
||||
class OAEPPaddingAlgorithmInstance extends Crypto::OAEPPaddingAlgorithmInstance,
|
||||
class OaepPaddingAlgorithmInstance extends Crypto::OaepPaddingAlgorithmInstance,
|
||||
KnownOpenSslPaddingConstantAlgorithmInstance
|
||||
{
|
||||
OAEPPaddingAlgorithmInstance() {
|
||||
this.(Crypto::PaddingAlgorithmInstance).getPaddingType() = Crypto::OAEP()
|
||||
OaepPaddingAlgorithmInstance() {
|
||||
this.(Crypto::PaddingAlgorithmInstance).getPaddingType() = KeyOpAlg::OAEP()
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getOAEPEncodingHashAlgorithm() {
|
||||
override Crypto::HashAlgorithmInstance getOaepEncodingHashAlgorithm() {
|
||||
none() //TODO
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getMGF1HashAlgorithm() {
|
||||
override Crypto::HashAlgorithmInstance getMgf1HashAlgorithm() {
|
||||
none() //TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class KnownOpenSslSignatureConstantAlgorithmInstance extends OpenSslAlgorithmIns
|
||||
none()
|
||||
}
|
||||
|
||||
override KeyOpAlg::Algorithm getAlgorithmType() {
|
||||
override KeyOpAlg::AlgorithmType getAlgorithmType() {
|
||||
knownOpenSslConstantToSignatureFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSslConstantToSignatureFamilyType(this, _) and
|
||||
|
||||
@@ -4,10 +4,10 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
/**
|
||||
* Cases like EVP_MD5(),
|
||||
* there is no input, rather it directly gets an algorithm
|
||||
* and returns it.
|
||||
* Also includes operations directly using an algorithm
|
||||
* A call that is considered to inherently 'consume' an algorithm value.
|
||||
* E.g., cases like EVP_MD5(),
|
||||
* where there is no input, rather it directly gets an algorithm
|
||||
* and returns it. Also includes operations directly using an algorithm
|
||||
* like AES_encrypt().
|
||||
*/
|
||||
class DirectAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer instanceof OpenSslAlgorithmCall
|
||||
|
||||
@@ -7,7 +7,7 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmI
|
||||
abstract class HashAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer { }
|
||||
|
||||
/**
|
||||
* EVP_Q_Digest directly consumes algorithm constant values
|
||||
* An EVP_Q_Digest directly consumes algorithm constant values
|
||||
*/
|
||||
class Evp_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer {
|
||||
Evp_Q_Digest_Algorithm_Consumer() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
//TODO: model as data on open APIs should be able to get common flows, and obviate some of this
|
||||
// e.g., copy/dup calls, need to ingest those models for openSSL and refactor.
|
||||
/**
|
||||
* In OpenSSL, flow between 'context' parameters is often used to
|
||||
* store state/config of how an operation will eventually be performed.
|
||||
* Tracing algorithms and configurations to operations therefore
|
||||
* requires tracing context parameters for many OpenSSL apis.
|
||||
*
|
||||
* This library provides a dataflow analysis to track context parameters
|
||||
* between any two functions accepting openssl context parameters.
|
||||
* The dataflow takes into consideration flowing through duplication and copy calls
|
||||
* as well as flow through flow killers (free/reset calls).
|
||||
*
|
||||
* TODO: we may need to revisit 'free' as a dataflow killer, depending on how
|
||||
* we want to model use after frees.
|
||||
*
|
||||
* This library also provides classes to represent context Types and relevant
|
||||
* arguments/expressions.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
/**
|
||||
* An openSSL CTX type, which is type for which the stripped underlying type
|
||||
* matches the pattern 'evp_%ctx_%st'.
|
||||
* This includes types like:
|
||||
* - EVP_CIPHER_CTX
|
||||
* - EVP_MD_CTX
|
||||
* - EVP_PKEY_CTX
|
||||
*/
|
||||
class CtxType extends Type {
|
||||
CtxType() {
|
||||
// It is possible for users to use the underlying type of the CTX variables
|
||||
// these have a name matching 'evp_%ctx_%st
|
||||
this.getUnspecifiedType().stripType().getName().matches("evp_%ctx_%st")
|
||||
or
|
||||
// In principal the above check should be sufficient, but in case of build mode none issues
|
||||
// i.e., if a typedef cannot be resolved,
|
||||
// or issues with properly stubbing test cases, we also explicitly check for the wrapping type defs
|
||||
// i.e., patterns matching 'EVP_%_CTX'
|
||||
exists(Type base | base = this or base = this.(DerivedType).getBaseType() |
|
||||
base.getName().matches("EVP_%_CTX")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A pointer to a CtxType
|
||||
*/
|
||||
class CtxPointerExpr extends Expr {
|
||||
CtxPointerExpr() {
|
||||
this.getType() instanceof CtxType and
|
||||
this.getType() instanceof PointerType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call argument of type CtxPointerExpr.
|
||||
*/
|
||||
class CtxPointerArgument extends CtxPointerExpr {
|
||||
CtxPointerArgument() { exists(Call c | c.getAnArgument() = this) }
|
||||
|
||||
Call getCall() { result.getAnArgument() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call returning a CtxPointerExpr.
|
||||
*/
|
||||
private class CtxPointerReturn extends CtxPointerExpr instanceof Call {
|
||||
Call getCall() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call whose target contains 'free' or 'reset' and has an argument of type
|
||||
* CtxPointerArgument.
|
||||
*/
|
||||
private class CtxClearCall extends Call {
|
||||
CtxClearCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%free%", "%reset%"]) and
|
||||
this.getAnArgument() instanceof CtxPointerArgument
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class CtxPassThroughCall extends Call {
|
||||
abstract DataFlow::Node getNode1();
|
||||
|
||||
abstract DataFlow::Node getNode2();
|
||||
}
|
||||
|
||||
/**
|
||||
* A call whose target contains 'copy' and has an argument of type
|
||||
* CtxPointerArgument.
|
||||
*/
|
||||
private class CtxCopyOutArgCall extends CtxPassThroughCall {
|
||||
DataFlow::Node n1;
|
||||
DataFlow::Node n2;
|
||||
|
||||
CtxCopyOutArgCall() {
|
||||
this.getTarget().getName().toLowerCase().matches("%copy%") and
|
||||
n1.asExpr() = this.getAnArgument() and
|
||||
n1.getType() instanceof CtxType and
|
||||
n2.asDefiningArgument() = this.getAnArgument() and
|
||||
n2.getType() instanceof CtxType and
|
||||
n1.asDefiningArgument() != n2.asExpr()
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result = n2 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call whose target contains 'dup' and has an argument of type
|
||||
* CtxPointerArgument.
|
||||
*/
|
||||
private class CtxCopyReturnCall extends CtxPassThroughCall, CtxPointerExpr {
|
||||
DataFlow::Node n1;
|
||||
|
||||
CtxCopyReturnCall() {
|
||||
this.getTarget().getName().toLowerCase().matches("%dup%") and
|
||||
n1.asExpr() = this.getAnArgument() and
|
||||
n1.getType() instanceof CtxType
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_paramgen` acts as a kind of pass through.
|
||||
* It's output pkey is eventually used in a new operation generating
|
||||
* a fresh context pointer (e.g., `EVP_PKEY_CTX_new`).
|
||||
* It is easier to model this as a pass through
|
||||
* than to model the flow from the paramgen to the new key generation.
|
||||
*/
|
||||
private class CtxParamGenCall extends CtxPassThroughCall {
|
||||
DataFlow::Node n1;
|
||||
DataFlow::Node n2;
|
||||
|
||||
CtxParamGenCall() {
|
||||
this.getTarget().getName() = "EVP_PKEY_paramgen" and
|
||||
n1.asExpr() = this.getArgument(0) and
|
||||
(
|
||||
n2.asExpr() = this.getArgument(1)
|
||||
or
|
||||
n2.asDefiningArgument() = this.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result = n2 }
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current node gets is an argument to a function
|
||||
* that returns a pointer type, immediately flow through.
|
||||
* NOTE: this passthrough is required if we allow
|
||||
* intermediate steps to go into variables that are not a CTX type.
|
||||
* See for example `CtxParamGenCall`.
|
||||
*/
|
||||
private class CallArgToCtxRet extends CtxPassThroughCall, CtxPointerExpr {
|
||||
DataFlow::Node n1;
|
||||
DataFlow::Node n2;
|
||||
|
||||
CallArgToCtxRet() {
|
||||
this.getAnArgument() = n1.asExpr() and
|
||||
n2.asExpr() = this
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result = n2 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A source Ctx of interest is any argument or return of type CtxPointerExpr.
|
||||
*/
|
||||
class CtxPointerSource extends CtxPointerExpr {
|
||||
CtxPointerSource() {
|
||||
this instanceof CtxPointerReturn or
|
||||
this instanceof CtxPointerArgument
|
||||
}
|
||||
|
||||
DataFlow::Node asNode() {
|
||||
result.asExpr() = this
|
||||
or
|
||||
result.asDefiningArgument() = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow from any CtxPointerSource to other CtxPointerSource.
|
||||
*/
|
||||
module OpenSslCtxSourceToSourceFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { exists(CtxPointerSource s | s.asNode() = source) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { exists(CtxPointerSource s | s.asNode() = sink) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(CtxPassThroughCall c | c.getNode1() = node1 and c.getNode2() = node2)
|
||||
}
|
||||
}
|
||||
|
||||
module OpenSslCtxSourceToArgumentFlow = DataFlow::Global<OpenSslCtxSourceToSourceFlowConfig>;
|
||||
|
||||
/**
|
||||
* Holds if there is a context flow from the source to the sink.
|
||||
*/
|
||||
predicate ctxSrcToSrcFlow(CtxPointerSource source, CtxPointerSource sink) {
|
||||
exists(DataFlow::Node a, DataFlow::Node b |
|
||||
OpenSslCtxSourceToArgumentFlow::flow(a, b) and
|
||||
a = source.asNode() and
|
||||
b = sink.asNode()
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
import experimental.quantum.Language
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import EVPPKeyCtxInitializer
|
||||
|
||||
/**
|
||||
* A base class for all EVP cipher operations.
|
||||
*/
|
||||
abstract class EvpCipherInitializer extends OperationStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and
|
||||
type = PrimaryAlgorithmIO() and
|
||||
// Constants that are not equal to zero or
|
||||
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
|
||||
// A zero (null) value typically indicates use of this operation step to initialize
|
||||
// other out parameters in a multi-step initialization.
|
||||
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for EVP cipher/decrypt/encrypt 'ex' operations.
|
||||
*/
|
||||
abstract class EvpEXInitializer extends EvpCipherInitializer {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
(
|
||||
// Constants that are not equal to zero or
|
||||
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
|
||||
// A zero (null) value typically indicates use of this operation step to initialize
|
||||
// other out parameters in a multi-step initialization.
|
||||
result.asExpr() = this.getArgument(3) and type = KeyIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(4) and type = IVorNonceIO()
|
||||
) and
|
||||
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for EVP cipher/decrypt/encrypt 'ex2' operations.
|
||||
*/
|
||||
abstract class EvpEX2Initializer extends EvpCipherInitializer {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = KeyIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(3) and type = IVorNonceIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to an EVP Cipher/Encrypt/Decrypt initialization operation.
|
||||
*/
|
||||
class EvpCipherEXInitCall extends EvpEXInitializer {
|
||||
EvpCipherEXInitCall() {
|
||||
this.getTarget().getName() in ["EVP_EncryptInit_ex", "EVP_DecryptInit_ex", "EVP_CipherInit_ex"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
// NOTE: for EncryptInit and DecryptInit there is no subtype arg
|
||||
// the subtype is determined automatically by the initializer based on the operation name
|
||||
this.getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result.asExpr() = this.getArgument(5) and
|
||||
type = KeyOperationSubtypeIO()
|
||||
}
|
||||
}
|
||||
|
||||
class Evp_Cipher_EX2_or_Simple_Init_Call extends EvpEX2Initializer {
|
||||
Evp_Cipher_EX2_or_Simple_Init_Call() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_EncryptInit_ex2", "EVP_DecryptInit_ex2", "EVP_CipherInit_ex2", "EVP_EncryptInit",
|
||||
"EVP_DecryptInit", "EVP_CipherInit"
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
this.getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result.asExpr() = this.getArgument(4) and
|
||||
type = KeyOperationSubtypeIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_Pkey_encrypt_init, EVP_Pkey_decrypt_init, or their 'ex' variants.
|
||||
*/
|
||||
class EvpPkeyEncryptDecryptInit extends OperationStep {
|
||||
EvpPkeyEncryptDecryptInit() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_encrypt_init", "EVP_PKEY_encrypt_init_ex", "EVP_PKEY_decrypt_init",
|
||||
"EVP_PKEY_decrypt_init_ex"
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
class EvpCipherInitSKeyCall extends EvpEX2Initializer {
|
||||
EvpCipherInitSKeyCall() { this.getTarget().getName() = "EVP_CipherInit_SKEY" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result = super.getInput(type)
|
||||
or
|
||||
result.asExpr() = this.getArgument(5) and
|
||||
type = KeyOperationSubtypeIO()
|
||||
}
|
||||
}
|
||||
|
||||
//EVP_PKEY_encrypt_init
|
||||
/**
|
||||
* A Call to EVP_Cipher/Encrypt/DecryptUpdate.
|
||||
* https://docs.openssl.org/3.2/man3/EVP_CipherUpdate
|
||||
*/
|
||||
class EvpCipherUpdateCall extends OperationStep {
|
||||
EvpCipherUpdateCall() {
|
||||
this.getTarget().getName() in ["EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base configuration for all EVP cipher operations.
|
||||
*/
|
||||
abstract class EvpCipherOperationFinalStep extends OperationStep {
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to EVP_Cipher.
|
||||
*/
|
||||
class EvpCipherCall extends EvpCipherOperationFinalStep {
|
||||
EvpCipherCall() { this.getTarget().getName() = "EVP_Cipher" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
super.getInput(type) = result
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
super.getOutput(type) = result
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to an EVP Cipher/Encrypt/Decrypt final operation.
|
||||
*/
|
||||
class EvpCipherFinalCall extends EvpCipherOperationFinalStep {
|
||||
EvpCipherFinalCall() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_EncryptFinal_ex", "EVP_DecryptFinal_ex", "EVP_CipherFinal_ex", "EVP_EncryptFinal",
|
||||
"EVP_DecryptFinal", "EVP_CipherFinal"
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
super.getOutput(type) = result
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and
|
||||
type = CiphertextIO()
|
||||
// TODO: could indicate text lengths here, as well
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a PKEY_encrypt or PKEY_decrypt operation.
|
||||
* https://docs.openssl.org/3.2/man3/EVP_PKEY_decrypt/
|
||||
* https://docs.openssl.org/3.2/man3/EVP_PKEY_encrypt
|
||||
*/
|
||||
class EvpPKeyCipherOperation extends EvpCipherOperationFinalStep {
|
||||
EvpPKeyCipherOperation() {
|
||||
this.getTarget().getName() in ["EVP_PKEY_encrypt", "EVP_PKEY_decrypt"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
super.getInput(type) = result
|
||||
or
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
super.getOutput(type) = result
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
|
||||
// TODO: could indicate text lengths here, as well
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An EVP cipher operation instance.
|
||||
* Any operation step that is a final operation step for EVP cipher operation steps.
|
||||
*/
|
||||
class EvpCipherOperationInstance extends Crypto::KeyOperationInstance instanceof EvpCipherOperationFinalStep
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
}
|
||||
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
result instanceof Crypto::TEncryptMode and
|
||||
super.getTarget().getName().toLowerCase().matches("%encrypt%")
|
||||
or
|
||||
result instanceof Crypto::TDecryptMode and
|
||||
super.getTarget().getName().toLowerCase().matches("%decrypt%")
|
||||
or
|
||||
super.getTarget().getName().toLowerCase().matches("%cipher%") and
|
||||
resolveKeyOperationSubTypeOperationStep(super
|
||||
.getDominatingInitializersToStep(KeyOperationSubtypeIO())) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
||||
super.getDominatingInitializersToStep(IVorNonceIO()).getInput(IVorNonceIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
super.getOutputStepFlowingToStep(CiphertextIO()).getOutput(CiphertextIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
private import experimental.quantum.Language
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
class ECKeyGenOperation extends OpenSslOperation, Crypto::KeyGenerationOperationInstance {
|
||||
ECKeyGenOperation() { this.(Call).getTarget().getName() = "EC_KEY_generate_key" }
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() {
|
||||
result.asExpr() = this.(Call).getArgument(0)
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
|
||||
none() // no explicit key size, inferred from algorithm
|
||||
}
|
||||
|
||||
override int getKeySizeFixed() {
|
||||
none()
|
||||
// TODO: marked as none as the operation itself has no key size, it
|
||||
// comes from the algorithm source, but note we could grab the
|
||||
// algorithm source and get the key size (see below).
|
||||
// We may need to reconsider what is the best approach here.
|
||||
// result =
|
||||
// this.getAnAlgorithmValueConsumer()
|
||||
// .getAKnownAlgorithmSource()
|
||||
// .(Crypto::EllipticCurveInstance)
|
||||
// .getKeySize()
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.CtxFlow
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
// TODO: need to add key consumer
|
||||
abstract class Evp_Cipher_Initializer extends EvpKeyOperationSubtypeInitializer,
|
||||
EvpPrimaryAlgorithmInitializer, EvpKeyInitializer, EvpIVInitializer
|
||||
{
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
}
|
||||
|
||||
abstract class Evp_EX_Initializer extends Evp_Cipher_Initializer {
|
||||
override Expr getKeyArg() {
|
||||
// Null key indicates the key is not actually set
|
||||
// This pattern can occur during a multi-step initialization
|
||||
// TODO/Note: not flowing 0 to the sink, assuming a direct use of NULL for now
|
||||
result = this.(Call).getArgument(3) and
|
||||
(exists(result.getValue()) implies result.getValue().toInt() != 0)
|
||||
}
|
||||
|
||||
override Expr getIVArg() {
|
||||
// Null IV indicates the IV is not actually set
|
||||
// This occurs given that setting the IV sometimes requires first setting the IV size.
|
||||
// TODO/Note: not flowing 0 to the sink, assuming a direct use of NULL for now
|
||||
result = this.(Call).getArgument(4) and
|
||||
(exists(result.getValue()) implies result.getValue().toInt() != 0)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Evp_EX2_Initializer extends Evp_Cipher_Initializer {
|
||||
override Expr getKeyArg() { result = this.(Call).getArgument(2) }
|
||||
|
||||
override Expr getIVArg() { result = this.(Call).getArgument(3) }
|
||||
}
|
||||
|
||||
class EvpCipherEXInitCall extends Evp_EX_Initializer {
|
||||
EvpCipherEXInitCall() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptInit_ex", "EVP_DecryptInit_ex", "EVP_CipherInit_ex"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getKeyOperationSubtypeArg() {
|
||||
// NOTE: for EncryptInit and DecryptInit there is no subtype arg
|
||||
// the subtype is determined automatically by the initializer based on the operation name
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result = this.(Call).getArgument(5)
|
||||
}
|
||||
}
|
||||
|
||||
// if this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
|
||||
// then result instanceof Crypto::TEncryptMode
|
||||
// else
|
||||
// if this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
|
||||
// then result instanceof Crypto::TDecryptMode
|
||||
class Evp_Cipher_EX2_or_Simple_Init_Call extends Evp_EX2_Initializer {
|
||||
Evp_Cipher_EX2_or_Simple_Init_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptInit_ex2", "EVP_DecryptInit_ex2", "EVP_CipherInit_ex2", "EVP_EncryptInit",
|
||||
"EVP_DecryptInit", "EVP_CipherInit"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getKeyOperationSubtypeArg() {
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result = this.(Call).getArgument(4)
|
||||
}
|
||||
}
|
||||
|
||||
class Evp_CipherInit_SKey_Call extends Evp_EX2_Initializer {
|
||||
Evp_CipherInit_SKey_Call() { this.(Call).getTarget().getName() = "EVP_CipherInit_SKEY" }
|
||||
|
||||
override Expr getKeyOperationSubtypeArg() { result = this.(Call).getArgument(5) }
|
||||
}
|
||||
|
||||
class Evp_Cipher_Update_Call extends EvpUpdate {
|
||||
Evp_Cipher_Update_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
|
||||
]
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* see: https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
|
||||
* Base configuration for all EVP cipher operations.
|
||||
*/
|
||||
abstract class Evp_Cipher_Operation extends EvpOperation, Crypto::KeyOperationInstance {
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
result instanceof Crypto::TEncryptMode and
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
|
||||
or
|
||||
result instanceof Crypto::TDecryptMode and
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
|
||||
or
|
||||
result = this.getInitCall().(EvpKeyOperationSubtypeInitializer).getKeyOperationSubtype() and
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipher%")
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
||||
this.getInitCall().(EvpIVInitializer).getIVArg() = result.asExpr()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
this.getInitCall().(EvpKeyInitializer).getKeyArg() = result.asExpr()
|
||||
// todo: or track to the EVP_PKEY_CTX_new
|
||||
}
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
result = EvpOperation.super.getOutputArtifact()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
result = EvpOperation.super.getInputConsumer()
|
||||
}
|
||||
}
|
||||
|
||||
class Evp_Cipher_Call extends EvpOperation, Evp_Cipher_Operation {
|
||||
Evp_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(2) }
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class Evp_Cipher_Final_Call extends EvpFinal, 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"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Output is both from update calls and from the final call.
|
||||
*/
|
||||
override Expr getOutputArg() {
|
||||
result = EvpFinal.super.getOutputArg()
|
||||
or
|
||||
result = Evp_Cipher_Operation.super.getOutputArg()
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* https://docs.openssl.org/3.2/man3/EVP_PKEY_decrypt/
|
||||
* https://docs.openssl.org/3.2/man3/EVP_PKEY_encrypt
|
||||
*/
|
||||
class Evp_PKey_Cipher_Operation extends Evp_Cipher_Operation {
|
||||
Evp_PKey_Cipher_Operation() {
|
||||
this.(Call).getTarget().getName() in ["EVP_PKEY_encrypt", "EVP_PKEY_decrypt"]
|
||||
}
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/**
|
||||
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
*/
|
||||
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.CtxFlow
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
class Evp_DigestInit_Variant_Calls extends EvpPrimaryAlgorithmInitializer {
|
||||
Evp_DigestInit_Variant_Calls() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_DigestInit", "EVP_DigestInit_ex", "EVP_DigestInit_ex2"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class Evp_Digest_Update_Call extends EvpUpdate {
|
||||
Evp_Digest_Update_Call() { this.(Call).getTarget().getName() = "EVP_DigestUpdate" }
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
class Evp_Q_Digest_Operation extends EvpOperation, Crypto::HashOperationInstance {
|
||||
Evp_Q_Digest_Operation() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override EvpInitializer getInitCall() {
|
||||
// This variant of digest does not use an init
|
||||
// and even if it were used, the init would be ignored/undefined
|
||||
none()
|
||||
}
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(5) }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
result = EvpOperation.super.getOutputArtifact()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
result = EvpOperation.super.getInputConsumer()
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class Evp_Digest_Operation extends EvpOperation, Crypto::HashOperationInstance {
|
||||
Evp_Digest_Operation() { this.(Call).getTarget().getName() = "EVP_Digest" }
|
||||
|
||||
// There is no context argument for this function
|
||||
override CtxPointerSource getContext() { none() }
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(4) }
|
||||
|
||||
override EvpPrimaryAlgorithmInitializer getInitCall() {
|
||||
// This variant of digest does not use an init
|
||||
// and even if it were used, the init would be ignored/undefined
|
||||
none()
|
||||
}
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(2) }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
result = EvpOperation.super.getOutputArtifact()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
result = EvpOperation.super.getInputConsumer()
|
||||
}
|
||||
}
|
||||
|
||||
class Evp_Digest_Final_Call extends EvpFinal, Crypto::HashOperationInstance {
|
||||
Evp_Digest_Final_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
|
||||
]
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
result = EvpFinal.super.getOutputArtifact()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
result = EvpFinal.super.getInputConsumer()
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.CtxFlow
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
class EvpKeyGenInitialize extends EvpPrimaryAlgorithmInitializer {
|
||||
EvpKeyGenInitialize() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_PKEY_keygen_init",
|
||||
"EVP_PKEY_paramgen_init"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the algorithm argument.
|
||||
* In this case the algorithm is encoded through the context argument.
|
||||
* The context may be directly created from an algorithm consumer,
|
||||
* or from a new operation off of a prior key. Either way,
|
||||
* we will treat this argument as the algorithm argument.
|
||||
*/
|
||||
override Expr getAlgorithmArg() { result = this.getContext() }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpKeyGenOperation extends EvpOperation, Crypto::KeyGenerationOperationInstance {
|
||||
DataFlow::Node keyResultNode;
|
||||
|
||||
EvpKeyGenOperation() {
|
||||
this.(Call).getTarget().getName() in ["EVP_RSA_gen", "EVP_PKEY_Q_keygen"] and
|
||||
keyResultNode.asExpr() = this
|
||||
or
|
||||
this.(Call).getTarget().getName() in ["EVP_PKEY_generate", "EVP_PKEY_keygen"] and
|
||||
keyResultNode.asDefiningArgument() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_Q_keygen" and
|
||||
result = this.(Call).getArgument(0)
|
||||
or
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
|
||||
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
|
||||
|
||||
override Expr getInputArg() { none() }
|
||||
|
||||
override Expr getOutputArg() { result = keyResultNode.asExpr() }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() { result = keyResultNode }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_Q_keygen" and
|
||||
result = DataFlow::exprNode(this.(Call).getArgument(3)) and
|
||||
// Arg 3 (0 based) is only a key size if the 'type' parameter is RSA, however,
|
||||
// as a crude approximation, assume that if the type of the argument is not a derived type
|
||||
// the argument must specify a key size (this is to avoid tracing if "rsa" is in the type parameter)
|
||||
not this.(Call).getArgument(3).getType().getUnderlyingType() instanceof DerivedType
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_RSA_gen" and
|
||||
result = DataFlow::exprNode(this.(Call).getArgument(0))
|
||||
or
|
||||
result = DataFlow::exprNode(this.getInitCall().(EvpKeySizeInitializer).getKeySizeArg())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_new_mac_key` that creatse a new generic MAC key.
|
||||
* Signature: EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e, const unsigned char *key, int keylen);
|
||||
*/
|
||||
class EvpNewMacKey extends EvpOperation, Crypto::KeyGenerationOperationInstance {
|
||||
DataFlow::Node keyResultNode;
|
||||
|
||||
EvpNewMacKey() {
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_new_mac_key" and keyResultNode.asExpr() = this
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { none() }
|
||||
|
||||
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TSymmetricKeyType() }
|
||||
|
||||
override Expr getOutputArg() { result = keyResultNode.asExpr() }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() { result = keyResultNode }
|
||||
|
||||
override Expr getInputArg() { none() }
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
|
||||
result = DataFlow::exprNode(this.(Call).getArgument(3))
|
||||
}
|
||||
}
|
||||
/// TODO: https://docs.openssl.org/3.0/man3/EVP_PKEY_new/#synopsis
|
||||
@@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import experimental.quantum.OpenSSL.CtxFlow
|
||||
private import OpenSSLOperations
|
||||
|
||||
/**
|
||||
@@ -14,49 +13,66 @@ private import OpenSSLOperations
|
||||
* These calls initialize the context from a prior key.
|
||||
* The key may be generated previously, or merely had it's
|
||||
* parameters set (e.g., `EVP_PKEY_paramgen`).
|
||||
* NOTE: for the case of `EVP_PKEY_paramgen`, these calls
|
||||
* are encoded as context passthroughs, and any operation
|
||||
* will get all associated initializers for the paramgen
|
||||
* at the final keygen operation automatically.
|
||||
*/
|
||||
class EvpNewKeyCtx extends EvpKeyInitializer {
|
||||
class EvpNewKeyCtx extends OperationStep instanceof Call {
|
||||
Expr keyArg;
|
||||
|
||||
EvpNewKeyCtx() {
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_new" and
|
||||
keyArg = this.(Call).getArgument(0)
|
||||
this.getTarget().getName() = "EVP_PKEY_CTX_new" and
|
||||
keyArg = this.getArgument(0)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
|
||||
keyArg = this.(Call).getArgument(1)
|
||||
this.getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
|
||||
keyArg = this.getArgument(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Context is returned
|
||||
*/
|
||||
override CtxPointerSource getContext() { result = this }
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = keyArg and type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = OsslLibContextIO()
|
||||
}
|
||||
|
||||
override Expr getKeyArg() { result = keyArg }
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = ContextIO() }
|
||||
|
||||
override OperationStepType getStepType() { result = ContextCreationStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to "EVP_PKEY_CTX_set_ec_paramgen_curve_nid".
|
||||
* Note that this is a primary algorithm as the pattenr is to specify an "EC" context,
|
||||
* then set the specific curve later. Although the curve is set later, it is the primary
|
||||
* algorithm intended for an operation.
|
||||
*/
|
||||
class EvpCtxSetPrimaryAlgorithmInitializer extends EvpPrimaryAlgorithmInitializer {
|
||||
EvpCtxSetPrimaryAlgorithmInitializer() {
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_ec_paramgen_curve_nid"
|
||||
class EvpCtxSetEcParamgenCurveNidInitializer extends OperationStep {
|
||||
EvpCtxSetEcParamgenCurveNidInitializer() {
|
||||
this.getTarget().getName() = "EVP_PKEY_CTX_set_ec_paramgen_curve_nid"
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
class EvpCtxSetHashAlgorithmInitializer extends EvpHashAlgorithmInitializer {
|
||||
EvpCtxSetHashAlgorithmInitializer() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
/**
|
||||
* A call to the following:
|
||||
* - `EVP_PKEY_CTX_set_signature_md`
|
||||
* - `EVP_PKEY_CTX_set_rsa_mgf1_md_name`
|
||||
* - `EVP_PKEY_CTX_set_rsa_mgf1_md`
|
||||
* - `EVP_PKEY_CTX_set_rsa_oaep_md_name`
|
||||
* - `EVP_PKEY_CTX_set_rsa_oaep_md`
|
||||
* - `EVP_PKEY_CTX_set_dsa_paramgen_md`
|
||||
* - `EVP_PKEY_CTX_set_dh_kdf_md`
|
||||
* - `EVP_PKEY_CTX_set_ecdh_kdf_md`
|
||||
*/
|
||||
class EvpCtxSetHashInitializer extends OperationStep {
|
||||
EvpCtxSetHashInitializer() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_signature_md", "EVP_PKEY_CTX_set_rsa_mgf1_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_mgf1_md", "EVP_PKEY_CTX_set_rsa_oaep_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_oaep_md", "EVP_PKEY_CTX_set_dsa_paramgen_md",
|
||||
@@ -64,56 +80,95 @@ class EvpCtxSetHashAlgorithmInitializer extends EvpHashAlgorithmInitializer {
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getHashAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpCtxSetKeySizeInitializer extends EvpKeySizeInitializer {
|
||||
Expr arg;
|
||||
|
||||
EvpCtxSetKeySizeInitializer() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_rsa_keygen_bits", "EVP_PKEY_CTX_set_dsa_paramgen_bits",
|
||||
"EVP_CIPHER_CTX_set_key_length"
|
||||
] and
|
||||
arg = this.(Call).getArgument(1)
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_mac_key" and
|
||||
arg = this.(Call).getArgument(2)
|
||||
result.asExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
}
|
||||
|
||||
override Expr getKeySizeArg() { result = arg }
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
class EvpCtxSetKeyInitializer extends EvpKeyInitializer {
|
||||
EvpCtxSetKeyInitializer() { this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_mac_key" }
|
||||
|
||||
override Expr getKeyArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpCtxSetPaddingInitializer extends EvpPaddingInitializer {
|
||||
EvpCtxSetPaddingInitializer() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_rsa_padding", "EVP_CIPHER_CTX_set_padding"
|
||||
/**
|
||||
* A call to `EVP_PKEY_CTX_set_rsa_keygen_bits`, `EVP_PKEY_CTX_set_dsa_paramgen_bits`,
|
||||
* or `EVP_CIPHER_CTX_set_key_length`.
|
||||
*/
|
||||
class EvpCtxSetKeySizeInitializer extends OperationStep {
|
||||
EvpCtxSetKeySizeInitializer() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_rsa_keygen_bits", "EVP_PKEY_CTX_set_dsa_paramgen_bits",
|
||||
"EVP_CIPHER_CTX_set_key_length"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getPaddingArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpCtxSetSaltLengthInitializer extends EvpSaltLengthInitializer {
|
||||
EvpCtxSetSaltLengthInitializer() {
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_rsa_pss_saltlen"
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = KeySizeIO()
|
||||
}
|
||||
|
||||
override Expr getSaltLengthArg() { result = this.(Call).getArgument(1) }
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
class EvpCtxSetMacKeyInitializer extends OperationStep {
|
||||
EvpCtxSetMacKeyInitializer() { this.getTarget().getName() = "EVP_PKEY_CTX_set_mac_key" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = KeySizeIO()
|
||||
or
|
||||
// the raw key that is configured into the output key
|
||||
result.asExpr() = this.getArgument(1) and type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
class EvpCtxSetPaddingInitializer extends OperationStep {
|
||||
EvpCtxSetPaddingInitializer() {
|
||||
this.getTarget().getName() in ["EVP_PKEY_CTX_set_rsa_padding", "EVP_CIPHER_CTX_set_padding"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = PaddingAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
class EvpCtxSetSaltLengthInitializer extends OperationStep {
|
||||
EvpCtxSetSaltLengthInitializer() {
|
||||
this.getTarget().getName() = "EVP_PKEY_CTX_set_rsa_pss_saltlen"
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = SaltLengthIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
/**
|
||||
* Provides classes for modeling OpenSSL's EVP signature operations
|
||||
*/
|
||||
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AvcFlow
|
||||
private import experimental.quantum.OpenSSL.CtxFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
||||
|
||||
// TODO: verification functions
|
||||
class EvpSignatureDigestInitializer extends EvpHashAlgorithmInitializer {
|
||||
Expr arg;
|
||||
|
||||
EvpSignatureDigestInitializer() {
|
||||
this.(Call).getTarget().getName() in ["EVP_DigestSignInit_ex", "EVP_DigestSignInit"] and
|
||||
arg = this.(Call).getArgument(2)
|
||||
or
|
||||
this.(Call).getTarget().getName() in ["EVP_SignInit", "EVP_SignInit_ex"] and
|
||||
arg = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
override Expr getHashAlgorithmArg() { result = arg }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpSignatureKeyInitializer extends EvpKeyInitializer {
|
||||
Expr arg;
|
||||
|
||||
EvpSignatureKeyInitializer() {
|
||||
this.(Call).getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
arg = this.(Call).getArgument(5)
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_DigestSignInit" and
|
||||
arg = this.(Call).getArgument(4)
|
||||
}
|
||||
|
||||
override Expr getKeyArg() { result = arg }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpSignaturePrimaryAlgorithmInitializer extends EvpPrimaryAlgorithmInitializer {
|
||||
Expr arg;
|
||||
|
||||
EvpSignaturePrimaryAlgorithmInitializer() {
|
||||
// signature algorithm
|
||||
this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
|
||||
arg = this.(Call).getArgument(1)
|
||||
or
|
||||
// configuration through the context argument
|
||||
this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init", "EVP_PKEY_sign_init_ex"] and
|
||||
arg = this.getContext()
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() { result = arg }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class Evp_Signature_Update_Call extends EvpUpdate {
|
||||
Evp_Signature_Update_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_DigestSignUpdate", "EVP_SignUpdate", "EVP_PKEY_sign_message_update"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Input is the message to sign.
|
||||
*/
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* We model output explicit output arguments as predicate to use it in constructors.
|
||||
* The predicate must cover all EVP_Signature_Operation subclasses.
|
||||
*/
|
||||
pragma[inline]
|
||||
private Expr signatureOperationOutputArg(Call call) {
|
||||
if call.getTarget().getName() = "EVP_SignFinal_ex"
|
||||
then result = call.getArgument(2)
|
||||
else result = call.getArgument(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* The base configuration for all EVP signature operations.
|
||||
*/
|
||||
abstract class EvpSignatureOperation extends EvpOperation, Crypto::SignatureOperationInstance {
|
||||
EvpSignatureOperation() {
|
||||
this.(Call).getTarget().getName().matches("EVP_%") and
|
||||
// NULL output argument means the call is to get the size of the signature and such call is not an operation
|
||||
(
|
||||
not exists(signatureOperationOutputArg(this).getValue())
|
||||
or
|
||||
signatureOperationOutputArg(this).getValue() != "0"
|
||||
)
|
||||
}
|
||||
|
||||
Expr getHashAlgorithmArg() {
|
||||
this.getInitCall().(EvpHashAlgorithmInitializer).getHashAlgorithmArg() = result
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg() = result
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||
AvcToCallArgFlow::flow(result.(OpenSslAlgorithmValueConsumer).getResultNode(),
|
||||
DataFlow::exprNode(this.getHashAlgorithmArg()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Signing, verification or unknown.
|
||||
*/
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
// TODO: if this KeyOperationSubtype does not match initialization call's KeyOperationSubtype then we found a bug
|
||||
if this.(Call).getTarget().getName().toLowerCase().matches("%sign%")
|
||||
then result instanceof Crypto::TSignMode
|
||||
else
|
||||
if this.(Call).getTarget().getName().toLowerCase().matches("%verify%")
|
||||
then result instanceof Crypto::TVerifyMode
|
||||
else result instanceof Crypto::TUnknownKeyOperationMode
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
||||
// TODO: some signing operations may have explicit nonce generators
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys provided in the initialization call or in a context are found by this method.
|
||||
* Keys in explicit arguments are found by overridden methods in extending classes.
|
||||
*/
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
result = DataFlow::exprNode(this.getInitCall().(EvpKeyInitializer).getKeyArg())
|
||||
}
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
result = EvpOperation.super.getOutputArtifact()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
result = EvpOperation.super.getInputConsumer()
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: only signing operations for now, change when verificaiton is added
|
||||
*/
|
||||
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() { none() }
|
||||
}
|
||||
|
||||
class Evp_Signature_Call extends EvpSignatureOperation {
|
||||
Evp_Signature_Call() { this.(Call).getTarget().getName() in ["EVP_DigestSign", "EVP_PKEY_sign"] }
|
||||
|
||||
/**
|
||||
* Output is the signature.
|
||||
*/
|
||||
override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
/**
|
||||
* Input is the message to sign.
|
||||
*/
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
}
|
||||
|
||||
class Evp_Signature_Final_Call extends EvpFinal, EvpSignatureOperation {
|
||||
Evp_Signature_Final_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_DigestSignFinal",
|
||||
"EVP_SignFinal_ex",
|
||||
"EVP_SignFinal",
|
||||
"EVP_PKEY_sign_message_final"
|
||||
]
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg() = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
// key provided as an argument
|
||||
this.(Call).getTarget().getName() in ["EVP_SignFinal", "EVP_SignFinal_ex"] and
|
||||
result = DataFlow::exprNode(this.(Call).getArgument(3))
|
||||
or
|
||||
// or find key in the initialization call
|
||||
result = EvpSignatureOperation.super.getKeyConsumer()
|
||||
}
|
||||
|
||||
/**
|
||||
* Output is the signature.
|
||||
*/
|
||||
override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
*/
|
||||
|
||||
private import experimental.quantum.Language
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
/**
|
||||
* A call to and EVP digest initializer, such as:
|
||||
* - `EVP_DigestInit`
|
||||
* - `EVP_DigestInit_ex`
|
||||
* - `EVP_DigestInit_ex2`
|
||||
*/
|
||||
class EvpDigestInitVariantCalls extends OperationStep instanceof Call {
|
||||
EvpDigestInitVariantCalls() {
|
||||
this.getTarget().getName() in ["EVP_DigestInit", "EVP_DigestInit_ex", "EVP_DigestInit_ex2"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_DigestUpdate`.
|
||||
*/
|
||||
class EvpDigestUpdateCall extends OperationStep instanceof Call {
|
||||
EvpDigestUpdateCall() { this.getTarget().getName() = "EVP_DigestUpdate" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for final digest operations.
|
||||
*/
|
||||
abstract class EvpFinalDigestOperationStep extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_Q_digest`
|
||||
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
*/
|
||||
class EvpQDigestOperation extends EvpFinalDigestOperationStep instanceof Call {
|
||||
EvpQDigestOperation() { this.getTarget().getName() = "EVP_Q_digest" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(5) and type = DigestIO()
|
||||
}
|
||||
}
|
||||
|
||||
class EvpDigestOperation extends EvpFinalDigestOperationStep instanceof Call {
|
||||
EvpDigestOperation() { this.getTarget().getName() = "EVP_Digest" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(4) and type = PrimaryAlgorithmIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(0) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(2) and type = DigestIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestFinal variants
|
||||
*/
|
||||
class EvpDigestFinalCall extends EvpFinalDigestOperationStep instanceof Call {
|
||||
EvpDigestFinalCall() {
|
||||
this.getTarget().getName() in ["EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and
|
||||
type = ContextIO()
|
||||
or
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = DigestIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An openssl digest final hash operation instance
|
||||
*/
|
||||
class EvpDigestFinalOperationInstance extends Crypto::HashOperationInstance instanceof EvpFinalDigestOperationStep
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
}
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
super.getOutputStepFlowingToStep(DigestIO()).getOutput(DigestIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
private import experimental.quantum.Language
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
/**
|
||||
* A call to EC_KEY_generate_key, which is used to generate an EC key pair.
|
||||
* Note: this is an operation, though the input parameter is a "EC_KEY*".
|
||||
* EC_KEY is really an empty context for a key that hasn't been generated, hence
|
||||
* we consider this an operation generating a key and not accepting a key input.
|
||||
*/
|
||||
class ECKeyGen extends OperationStep instanceof Call {
|
||||
//, Crypto::KeyGenerationOperationInstance {
|
||||
ECKeyGen() { this.(Call).getTarget().getName() = "EC_KEY_generate_key" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.(Call).getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
|
||||
|
||||
override OperationStepType getStepType() { result = ContextCreationStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_PKEY_keygen_init or EVP_PKEY_paramgen_init.
|
||||
*/
|
||||
class EvpKeyGenInitialize extends OperationStep {
|
||||
EvpKeyGenInitialize() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_keygen_init",
|
||||
"EVP_PKEY_paramgen_init"
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
abstract class KeyGenFinalOperationStep extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_Q_keygen`
|
||||
*/
|
||||
class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
EvpPKeyQKeyGen() { this.getTarget().getName() = "EVP_PKEY_Q_keygen" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this and type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// When arg 3 is a derived type, it is a curve name, otherwise it is a key size for RSA if provided
|
||||
// and arg 2 is the algorithm type
|
||||
this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
|
||||
result.asExpr() = this.getArgument(3) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
|
||||
result.asExpr() = this.getArgument(2) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
|
||||
result.asExpr() = this.getArgument(3) and
|
||||
type = KeySizeIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_RSA_gen`
|
||||
*/
|
||||
class EvpRsaGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
EvpRsaGen() { this.getTarget().getName() = "EVP_RSA_gen" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to RSA_generate_key
|
||||
*/
|
||||
class RsaGenerateKey extends KeyGenFinalOperationStep instanceof Call {
|
||||
RsaGenerateKey() { this.getTarget().getName() = "RSA_generate_key" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to RSA_generate_key_ex
|
||||
*/
|
||||
class RsaGenerateKeyEx extends KeyGenFinalOperationStep instanceof Call {
|
||||
RsaGenerateKeyEx() { this.getTarget().getName() = "RSA_generate_key_ex" }
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(0) and type = KeyIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
// arg 0 comes in as a blank RSA key, which we consider a context,
|
||||
// on output it is considered a key
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_generate` or `EVP_PKEY_keygen`.
|
||||
*/
|
||||
class EvpPkeyGen extends KeyGenFinalOperationStep instanceof Call {
|
||||
EvpPkeyGen() { this.getTarget().getName() in ["EVP_PKEY_generate", "EVP_PKEY_keygen"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asDefiningArgument() = this.getArgument(1) and type = KeyIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `EVP_PKEY_new_mac_key` that creates a new generic MAC key.
|
||||
* - EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e, const unsigned char *key, int keylen);
|
||||
*/
|
||||
class EvpNewMacKey extends KeyGenFinalOperationStep {
|
||||
EvpNewMacKey() { this.getTarget().getName() = "EVP_PKEY_new_mac_key" }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// the raw key that is configured into the output key
|
||||
result.asExpr() = this.getArgument(2) and type = KeyIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(3) and type = KeySizeIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this and type = KeyIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: https://docs.openssl.org/3.0/man3/EVP_PKEY_new/#synopsis
|
||||
/**
|
||||
* An `KeyGenerationOperationInstance` for the for all key gen final operation steps.
|
||||
*/
|
||||
class KeyGenOperationInstance extends Crypto::KeyGenerationOperationInstance instanceof KeyGenFinalOperationStep
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
}
|
||||
|
||||
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() {
|
||||
super.getOutputStepFlowingToStep(KeyIO()).getOutput(KeyIO()) = result
|
||||
}
|
||||
|
||||
override predicate hasKeyValueConsumer() {
|
||||
exists(OperationStep s | s.flowsToOperationStep(this) and s.setsValue(KeyIO()))
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
|
||||
super.getDominatingInitializersToStep(KeySizeIO()).getInput(KeySizeIO()) = result
|
||||
}
|
||||
|
||||
override int getKeySizeFixed() {
|
||||
none()
|
||||
// TODO: marked as none as the operation itself has no key size, it
|
||||
// comes from the algorithm source, but note we could grab the
|
||||
// algorithm source and get the key size (see below).
|
||||
// We may need to reconsider what is the best approach here.
|
||||
// result =
|
||||
// this.getAnAlgorithmValueConsumer()
|
||||
// .getAKnownAlgorithmSource()
|
||||
// .(Crypto::EllipticCurveInstance)
|
||||
// .getKeySize()
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyValueConsumer() {
|
||||
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
|
||||
}
|
||||
}
|
||||
@@ -1,316 +1,523 @@
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AvcFlow
|
||||
private import experimental.quantum.OpenSSL.CtxFlow
|
||||
private import experimental.quantum.OpenSSL.KeyFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
// Importing these intializers here to ensure the are part of any model that is
|
||||
// using OpenSslOperationBase. This further ensures that initializers are tied to opeartions
|
||||
// even if only importing the operation by itself.
|
||||
import EVPPKeyCtxInitializer
|
||||
|
||||
/**
|
||||
* An openSSL CTX type, which is type for which the stripped underlying type
|
||||
* matches the pattern 'evp_%ctx_%st'.
|
||||
* This includes types like:
|
||||
* - EVP_CIPHER_CTX
|
||||
* - EVP_MD_CTX
|
||||
* - EVP_PKEY_CTX
|
||||
*/
|
||||
class CtxType extends Type {
|
||||
CtxType() {
|
||||
// It is possible for users to use the underlying type of the CTX variables
|
||||
// these have a name matching 'evp_%ctx_%st
|
||||
this.getUnspecifiedType().stripType().getName().matches("evp_%ctx_%st")
|
||||
or
|
||||
// In principal the above check should be sufficient, but in case of build mode none issues
|
||||
// i.e., if a typedef cannot be resolved,
|
||||
// or issues with properly stubbing test cases, we also explicitly check for the wrapping type defs
|
||||
// i.e., patterns matching 'EVP_%_CTX'
|
||||
exists(Type base | base = this or base = this.(DerivedType).getBaseType() |
|
||||
base.getName().matches("EVP_%_CTX")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A pointer to a CtxType
|
||||
*/
|
||||
class CtxPointerExpr extends Expr {
|
||||
CtxPointerExpr() {
|
||||
this.getType() instanceof CtxType and
|
||||
this.getType() instanceof PointerType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call argument of type CtxPointerExpr.
|
||||
*/
|
||||
class CtxPointerArgument extends CtxPointerExpr {
|
||||
CtxPointerArgument() { exists(Call c | c.getAnArgument() = this) }
|
||||
|
||||
Call getCall() { result.getAnArgument() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of inputs and ouputs for an `OperationStep`.
|
||||
*/
|
||||
newtype TIOType =
|
||||
CiphertextIO() or
|
||||
// Used for typical CTX types, but not for OSSL_PARAM or OSSL_LIB_CTX
|
||||
// For OSSL_PARAM and OSSL_LIB_CTX use of OsslParamIO and OsslLibContextIO
|
||||
ContextIO() or
|
||||
DigestIO() or
|
||||
HashAlgorithmIO() or
|
||||
IVorNonceIO() or
|
||||
KeyIO() or
|
||||
KeyOperationSubtypeIO() or
|
||||
KeySizeIO() or
|
||||
// Used for OSSL_LIB_CTX
|
||||
OsslLibContextIO() or
|
||||
// Used for OSSL_PARAM
|
||||
OsslParamIO() or
|
||||
MacIO() or
|
||||
PaddingAlgorithmIO() or
|
||||
// Plaintext also includes a message for digest, signature, verification, and mac generation
|
||||
PlaintextIO() or
|
||||
PrimaryAlgorithmIO() or
|
||||
RandomSourceIO() or
|
||||
SaltLengthIO() or
|
||||
SeedIO() or
|
||||
SignatureIO()
|
||||
|
||||
private string ioTypeToString(TIOType t) {
|
||||
t = CiphertextIO() and result = "CiphertextIO"
|
||||
or
|
||||
t = ContextIO() and result = "ContextIO"
|
||||
or
|
||||
t = DigestIO() and result = "DigestIO"
|
||||
or
|
||||
t = HashAlgorithmIO() and result = "HashAlgorithmIO"
|
||||
or
|
||||
t = IVorNonceIO() and result = "IVorNonceIO"
|
||||
or
|
||||
t = KeyIO() and result = "KeyIO"
|
||||
or
|
||||
t = KeyOperationSubtypeIO() and result = "KeyOperationSubtypeIO"
|
||||
or
|
||||
t = KeySizeIO() and result = "KeySizeIO"
|
||||
or
|
||||
t = OsslLibContextIO() and result = "OsslLibContextIO"
|
||||
or
|
||||
t = OsslParamIO() and result = "OsslParamIO"
|
||||
or
|
||||
t = MacIO() and result = "MacIO"
|
||||
or
|
||||
t = PaddingAlgorithmIO() and result = "PaddingAlgorithmIO"
|
||||
or
|
||||
t = PlaintextIO() and result = "PlaintextIO"
|
||||
or
|
||||
t = PrimaryAlgorithmIO() and result = "PrimaryAlgorithmIO"
|
||||
or
|
||||
t = RandomSourceIO() and result = "RandomSourceIO"
|
||||
or
|
||||
t = SaltLengthIO() and result = "SaltLengthIO"
|
||||
or
|
||||
t = SeedIO() and result = "SeedIO"
|
||||
or
|
||||
t = SignatureIO() and result = "SignatureIO"
|
||||
}
|
||||
|
||||
class IOType extends TIOType {
|
||||
string toString() {
|
||||
result = ioTypeToString(this)
|
||||
or
|
||||
not exists(ioTypeToString(this)) and result = "UnknownIOType"
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: add more initializers as needed
|
||||
/**
|
||||
* The type of step in an `OperationStep`.
|
||||
* - `ContextCreationStep`: the creation of a context from an algorithm or key.
|
||||
* for example `EVP_MD_CTX_create(EVP_sha256())` or `EVP_PKEY_CTX_new(pkey, NULL)`
|
||||
* - `InitializerStep`: the initialization of an operation through some sort of shared/accumulated context
|
||||
* for example `EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)`
|
||||
* - `UpdateStep`: any operation that has and update/final paradigm, the update represents an intermediate step in an operation,
|
||||
* such as `EVP_DigestUpdate(ctx, data, len)`
|
||||
* - `FinalStep`: an ultimate operation step. This may be an explicit 'final' in an update/final paradigm, but not necessarily.
|
||||
* Any operation that does nto operate through an update/final paradigm is considered a final step.
|
||||
*/
|
||||
newtype OperationStepType =
|
||||
// Context creation captures cases where a context is created from an algorithm or key
|
||||
//
|
||||
ContextCreationStep() or
|
||||
InitializerStep() or
|
||||
UpdateStep() or
|
||||
FinalStep()
|
||||
|
||||
/**
|
||||
* A step in configuring an operation.
|
||||
* Captures creation of contexts from algorithms or keys,
|
||||
* initalization of configurations on contexts,
|
||||
* update operations (intermediate steps in an operation)
|
||||
* and the operation itself.
|
||||
*
|
||||
* NOTE: if an operation is configured through a means other than a call
|
||||
* e.g., a pattern like ctx->alg = EVP_sha256()
|
||||
* then this class will need to be modified to account for that paradigm.
|
||||
* Currently, this is not a known pattern in OpenSSL.
|
||||
*/
|
||||
abstract class OperationStep extends Call {
|
||||
/**
|
||||
* Gets the output nodes from the given operation step.
|
||||
* These are the nodes that flow connecting this step
|
||||
* to any other step in the operation should follow.
|
||||
*/
|
||||
abstract DataFlow::Node getOutput(IOType type);
|
||||
|
||||
/**
|
||||
* Gets any output node from the given operation step.
|
||||
*/
|
||||
final DataFlow::Node getAnOutput() { result = this.getOutput(_) }
|
||||
|
||||
/**
|
||||
* Gets the input nodes for the given operation step.
|
||||
*/
|
||||
abstract DataFlow::Node getInput(IOType type);
|
||||
|
||||
/**
|
||||
* Gets any input node for the given operation step.
|
||||
*/
|
||||
final DataFlow::Node getAnInput() { result = this.getInput(_) }
|
||||
|
||||
/**
|
||||
* Gets the type of the step, e.g., ContextCreationStep, InitializerStep, UpdateStep, FinalStep.
|
||||
*/
|
||||
abstract OperationStepType getStepType();
|
||||
|
||||
/**
|
||||
* Holds if this operation step flows to the given `OperationStep` `sink`.
|
||||
* If `sink` is `this`, then this holds true.
|
||||
*/
|
||||
predicate flowsToOperationStep(OperationStep sink) {
|
||||
sink = this or
|
||||
OperationStepFlow::flow(this.getAnOutput(), sink.getAnInput())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this operation step flows from the given `OperationStep` (`source`).
|
||||
* If `source` is `this`, then this holds true.
|
||||
*/
|
||||
predicate flowsFromOperationStep(OperationStep source) {
|
||||
source = this or
|
||||
OperationStepFlow::flow(source.getAnOutput(), this.getAnInput())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this operation step sets a value of the given `IOType`.
|
||||
*/
|
||||
predicate setsValue(IOType type) { exists(this.getInput(type)) }
|
||||
|
||||
/**
|
||||
* Gets operation steps that flow to `this` and set the given `IOType`.
|
||||
* This checks for the last initializers that flow to the `this`,
|
||||
* i.e., if a value is set then re-set, the last set operation step is returned,
|
||||
* not both.
|
||||
* Note: Any 'update' that sets a value is not considered to be 'resetting' an input.
|
||||
* I.e., there is a difference between changing a configuration before use and
|
||||
* the operation allows for multiple inputs (like plaintext for cipher update calls before final).
|
||||
*/
|
||||
OperationStep getDominatingInitializersToStep(IOType type) {
|
||||
result.flowsToOperationStep(this) and
|
||||
result.setsValue(type) and
|
||||
(
|
||||
// Do not consider a 'reset' to occur on updates
|
||||
result.getStepType() = UpdateStep()
|
||||
or
|
||||
not exists(OperationStep reset |
|
||||
result != reset and
|
||||
reset.setsValue(type) and
|
||||
reset.flowsToOperationStep(this) and
|
||||
result.flowsToOperationStep(reset)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all output of `type` that flow to `this`
|
||||
* if `this` is a final step and the output is not from
|
||||
* a separate final step.
|
||||
*/
|
||||
OperationStep getOutputStepFlowingToStep(IOType type) {
|
||||
this.getStepType() = FinalStep() and
|
||||
result.flowsToOperationStep(this) and
|
||||
exists(result.getOutput(type)) and
|
||||
(result = this or result.getStepType() != FinalStep())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an AVC for the primary algorithm for this operation.
|
||||
* A primary algorithm is an AVC that flows to a ctx input directly or
|
||||
* an AVC that flows to a primary algorithm input directly.
|
||||
* See `AvcContextCreationStep` for details about resetting scenarios.
|
||||
* Gets the first OperationStep an AVC flows to. If a context input,
|
||||
* the AVC is considered primary.
|
||||
* If a primary algorithm input, then get the last set primary algorithm
|
||||
* operation step (dominating operation step, see `getDominatingInitializersToStep`).
|
||||
*/
|
||||
Crypto::AlgorithmValueConsumer getPrimaryAlgorithmValueConsumer() {
|
||||
exists(DataFlow::Node src, DataFlow::Node sink, IOType t, OperationStep avcSucc |
|
||||
(t = PrimaryAlgorithmIO() or t = ContextIO()) and
|
||||
avcSucc.flowsToOperationStep(this) and
|
||||
src.asExpr() = result and
|
||||
sink = avcSucc.getInput(t) and
|
||||
AvcToOperationStepFlow::flow(src, sink) and
|
||||
(
|
||||
// Case 1: the avcSucc step is a dominating initialization step
|
||||
t = PrimaryAlgorithmIO() and
|
||||
avcSucc = this.getDominatingInitializersToStep(PrimaryAlgorithmIO())
|
||||
or
|
||||
// Case 2: the succ is a context input (any avcSucc is valid)
|
||||
t = ContextIO()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the algorithm value consumer for an input to `this` operation step
|
||||
* of the given `type`.
|
||||
* TODO: generalize to use this for `getPrimaryAlgorithmValueConsumer`
|
||||
*/
|
||||
Crypto::AlgorithmValueConsumer getAlgorithmValueConsumerForInput(IOType type) {
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
AvcToOperationStepFlow::flow(src, sink) and
|
||||
src.asExpr() = result and
|
||||
sink = this.getInput(type)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An AVC is considered to output a 'context type', however,
|
||||
* each AVC has it's own output types in practice.
|
||||
* Some output algorithm containers (`EVP_get_cipherbyname`)
|
||||
* some output explicit contexts (`EVP_PKEY_CTX_new_from_name`).
|
||||
* The output of an AVC cannot be determined to be a primary algorithm (PrimaryAlgorithmIO), that depends
|
||||
* on the use of the AVC output.
|
||||
* The use is assumed to be of two forms:
|
||||
* - The AVC output flows to a known input that accepts an algorithm
|
||||
* e.g., `EVP_DigestInit(ctx, type)` the `type` parameter is known to be the primary algorithm.
|
||||
* `EVP_SignInit(ctx, type)` the `type` parameter is known to be a digest algorithm for the signature.
|
||||
* - The AVC output flows to a context initialization step
|
||||
* e.g., `pkey_ctx = EVP_PKEY_CTX_new_from_name(libctx, name, propquery)` this is an AVC call, but the
|
||||
* API says the output is a context. It is consumed typically by something like:
|
||||
* `ctx = EVP_PKEY_keygen_init(pkey_ctx)`, but note I cannot consider the `pkey_ctx` parameter to always be a primary algorithm,
|
||||
* a key gen can be inited by a prior key as well, e.g., `ctx = EVP_PKEY_CTX_new(pkey, NULL)`.
|
||||
* Hence, these initialization steps take in a context that may have come from an AVC or something else,
|
||||
* and therefore cannot be considered a primary algorithm.
|
||||
* Assumption: The first operation step an AVC flows to will be of the above two forms.
|
||||
* Resetting Algorithm Concerns and Assumptions:
|
||||
* What if a user resets the algorithm through another AVC call?
|
||||
* How would we detect that and only look at the 'dominating' (last set) AVC?
|
||||
* From an AVC, always assess the first operation step it flows to.
|
||||
* If the first step is to a context input, then we assume that reset is not possible in the same path.
|
||||
* I.e., a user cannot reset the algorithm without starting an entirely new operation step chain.
|
||||
* See the use patterns for `pkey_ctx = EVP_PKEY_CTX_new_from_name(...)` mentioned above. A user cannot
|
||||
* reset the algorithm without calling a new `ctx = EVP_PKEY_keygen_init(pkey_ctx)`,
|
||||
* i.e., subsequent flow follows the `ctx` output.
|
||||
* If the first step is to any other input, then we use the `getDominatingInitializersToStep`
|
||||
* to find the last AVC that set the algorithm for the operation step.
|
||||
* Domination checks must occur at an operation step (e.g., at a final operation).
|
||||
* This operation step does not find the dominating AVC.
|
||||
* If a primary algorithm is explicitly set and and AVC is set through a context input,
|
||||
* we will use both cases as primary inputs.
|
||||
*/
|
||||
class AvcContextCreationStep extends OperationStep instanceof OpenSslAlgorithmValueConsumer {
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
type = ContextIO() and result = super.getResultNode()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) { none() }
|
||||
|
||||
override OperationStepType getStepType() { result = ContextCreationStep() }
|
||||
}
|
||||
|
||||
abstract private class CtxPassThroughCall extends Call {
|
||||
abstract DataFlow::Node getNode1();
|
||||
|
||||
abstract DataFlow::Node getNode2();
|
||||
}
|
||||
|
||||
/**
|
||||
* A call whose target contains 'free' or 'reset' and has an argument of type
|
||||
* CtxPointerArgument.
|
||||
*/
|
||||
private class CtxClearCall extends Call {
|
||||
CtxClearCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%free%", "%reset%"]) and
|
||||
this.getAnArgument() instanceof CtxPointerArgument
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call whose target contains 'copy' and has an argument of type
|
||||
* CtxPointerArgument.
|
||||
*/
|
||||
private class CtxCopyOutArgCall extends CtxPassThroughCall {
|
||||
DataFlow::Node n1;
|
||||
DataFlow::Node n2;
|
||||
|
||||
CtxCopyOutArgCall() {
|
||||
this.getTarget().getName().toLowerCase().matches("%copy%") and
|
||||
n1.asExpr() = this.getAnArgument() and
|
||||
n1.getType() instanceof CtxType and
|
||||
n2.asDefiningArgument() = this.getAnArgument() and
|
||||
n2.getType() instanceof CtxType and
|
||||
n1.asDefiningArgument() != n2.asExpr()
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result = n2 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call whose target contains 'dup' and has an argument of type
|
||||
* CtxPointerArgument.
|
||||
*/
|
||||
private class CtxCopyReturnCall extends CtxPassThroughCall, CtxPointerExpr {
|
||||
DataFlow::Node n1;
|
||||
|
||||
CtxCopyReturnCall() {
|
||||
this.getTarget().getName().toLowerCase().matches("%dup%") and
|
||||
n1.asExpr() = this.getAnArgument() and
|
||||
n1.getType() instanceof CtxType
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
// TODO: is this still needed?
|
||||
/**
|
||||
* A call to `EVP_PKEY_paramgen` acts as a kind of pass through.
|
||||
* It's output pkey is eventually used in a new operation generating
|
||||
* a fresh context pointer (e.g., `EVP_PKEY_CTX_new`).
|
||||
* It is easier to model this as a pass through
|
||||
* than to model the flow from the paramgen to the new key generation.
|
||||
*/
|
||||
private class CtxParamGenCall extends CtxPassThroughCall {
|
||||
DataFlow::Node n1;
|
||||
DataFlow::Node n2;
|
||||
|
||||
CtxParamGenCall() {
|
||||
this.getTarget().getName() = "EVP_PKEY_paramgen" and
|
||||
n1.asExpr() = this.getArgument(0) and
|
||||
(
|
||||
n2.asExpr() = this.getArgument(1)
|
||||
or
|
||||
n2.asDefiningArgument() = this.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result = n2 }
|
||||
}
|
||||
|
||||
//TODO: I am not sure CallArgToCtxRet is needed anymore
|
||||
/**
|
||||
* If the current node is an argument to a function
|
||||
* that returns a pointer type, immediately flow through.
|
||||
* NOTE: this passthrough is required if we allow
|
||||
* intermediate steps to go into variables that are not a CTX type.
|
||||
* See for example `CtxParamGenCall`.
|
||||
*/
|
||||
private class CallArgToCtxRet extends CtxPassThroughCall, CtxPointerExpr {
|
||||
DataFlow::Node n1;
|
||||
DataFlow::Node n2;
|
||||
|
||||
CallArgToCtxRet() {
|
||||
this.getAnArgument() = n1.asExpr() and
|
||||
n2.asExpr() = this
|
||||
}
|
||||
|
||||
override DataFlow::Node getNode1() { result = n1 }
|
||||
|
||||
override DataFlow::Node getNode2() { result = n2 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow configuration from any non-final `OperationStep` to any other `OperationStep`.
|
||||
*/
|
||||
module OperationStepFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(OperationStep s |
|
||||
s.getAnOutput() = source or
|
||||
s.getAnInput() = source
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(OperationStep s |
|
||||
s.getAnInput() = sink or
|
||||
s.getAnOutput() = sink
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(CtxPassThroughCall c | c.getNode1() = node1 and c.getNode2() = node2)
|
||||
or
|
||||
// Flow out through all outputs from an operation step if more than one output
|
||||
// is defined.
|
||||
exists(OperationStep s | s.getAnInput() = node1 and s.getAnOutput() = node2)
|
||||
// TODO: consideration for additional alises defined as follows:
|
||||
// if an output from an operation step itself flows from the output of another operation step
|
||||
// then the source of that flow's outputs (all of them) are potential aliases
|
||||
}
|
||||
}
|
||||
|
||||
module OperationStepFlow = DataFlow::Global<OperationStepFlowConfig>;
|
||||
|
||||
/**
|
||||
* A flow from AVC to the first `OperationStep` the AVC reaches as an input.
|
||||
*/
|
||||
module AvcToOperationStepFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(AvcContextCreationStep s | s.getAnOutput() = source)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { exists(OperationStep s | s.getAnInput() = sink) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
* Only get the first operation step encountered.
|
||||
*/
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(CtxPassThroughCall c | c.getNode1() = node1 and c.getNode2() = node2)
|
||||
}
|
||||
}
|
||||
|
||||
module AvcToOperationStepFlow = DataFlow::Global<AvcToOperationStepFlowConfig>;
|
||||
|
||||
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EvpKeyOperationSubtypeInitializer initCall |
|
||||
sink.asExpr() = initCall.getKeyOperationSubtypeArg()
|
||||
)
|
||||
exists(OperationStep s | sink = s.getInput(KeyOperationSubtypeIO()))
|
||||
}
|
||||
}
|
||||
|
||||
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
|
||||
|
||||
private predicate argToAvc(Expr arg, Crypto::AlgorithmValueConsumer avc) {
|
||||
// NOTE: because we trace through keys to their sources we must consider that the arg is an avc
|
||||
// Consider this example:
|
||||
// EVP_PKEY *pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, key_len);
|
||||
// The key may trace into a signing operation. Tracing through the key we will get the arg taking `EVP_PKEY_HMAC`
|
||||
// as the algorithm value consumer (the input node of the AVC). The output node of this AVC
|
||||
// is the call return of `EVP_PKEY_new_mac_key`. If we trace from the AVC result to
|
||||
// the input argument this will not be possible (from the return to the call argument is a backwards flow).
|
||||
// Therefore, we must consider the input node of the AVC as the argument.
|
||||
// This should only occur due to tracing through keys to find configuration data.
|
||||
avc.getInputNode().asExpr() = arg
|
||||
private Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
|
||||
i = 0 and
|
||||
result instanceof Crypto::TEncryptMode
|
||||
or
|
||||
AvcToCallArgFlow::flow(avc.(OpenSslAlgorithmValueConsumer).getResultNode(),
|
||||
DataFlow::exprNode(arg))
|
||||
i = 1 and result instanceof Crypto::TDecryptMode
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for all OpenSsl operations.
|
||||
*/
|
||||
abstract class OpenSslOperation extends Crypto::OperationInstance instanceof Call {
|
||||
/**
|
||||
* Gets the argument that specifies the algorithm for the operation.
|
||||
* This argument might not be immediately present at the specified operation.
|
||||
* For example, it might be set in an initialization call.
|
||||
* Modelers of the operation are resonsible for linking the operation to any
|
||||
* initialization calls, and providing that argument as a returned value here.
|
||||
*/
|
||||
abstract Expr getAlgorithmArg();
|
||||
|
||||
/**
|
||||
* Algorithm is specified in initialization call or is implicitly established by the key.
|
||||
*/
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
argToAvc(this.getAlgorithmArg(), result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to an initialization function for an operation.
|
||||
* These are not operations in the sense of Crypto::OperationInstance,
|
||||
* but they are used to initialize the context for the operation.
|
||||
* There may be multiple initialization calls for the same operation.
|
||||
* Intended for use with EvPOperation.
|
||||
*/
|
||||
abstract class EvpInitializer extends Call {
|
||||
/**
|
||||
* Gets the context argument or return that ties together initialization, updates and/or final calls.
|
||||
* The context is the context coming into the initializer and is the output as well.
|
||||
* This is assumed to be the same argument.
|
||||
*/
|
||||
abstract CtxPointerSource getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to initialize a key size.
|
||||
*/
|
||||
abstract class EvpKeySizeInitializer extends EvpInitializer {
|
||||
abstract Expr getKeySizeArg();
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to initialize a key operation subtype.
|
||||
*/
|
||||
abstract class EvpKeyOperationSubtypeInitializer extends EvpInitializer {
|
||||
abstract Expr getKeyOperationSubtypeArg();
|
||||
|
||||
private Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
|
||||
i = 0 and
|
||||
result instanceof Crypto::TEncryptMode
|
||||
or
|
||||
i = 1 and result instanceof Crypto::TDecryptMode
|
||||
}
|
||||
|
||||
Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
exists(DataFlow::Node a, DataFlow::Node b |
|
||||
EncValToInitEncArgFlow::flow(a, b) and
|
||||
b.asExpr() = this.getKeyOperationSubtypeArg() and
|
||||
result = this.intToCipherOperationSubtype(a.asExpr().getValue().toInt())
|
||||
)
|
||||
or
|
||||
// Infer the subtype from the initialization call, and ignore the argument
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%") and
|
||||
result instanceof Crypto::TEncryptMode
|
||||
or
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%") and
|
||||
result instanceof Crypto::TDecryptMode
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An primary algorithm initializer initializes the primary algorithm for a given operation.
|
||||
* For example, for a signing operation, the algorithm initializer may initialize algorithms
|
||||
* like RSA. Other algorithsm may be initialized on an operation, as part of a larger
|
||||
* operation/protocol. For example, hashing operations on signing operations; however,
|
||||
* these are not the primary algorithm. Any other algorithms initialized on an operation
|
||||
* require a specialized initializer, such as EvpHashAlgorithmInitializer.
|
||||
*/
|
||||
abstract class EvpPrimaryAlgorithmInitializer extends EvpInitializer {
|
||||
abstract Expr getAlgorithmArg();
|
||||
|
||||
Crypto::AlgorithmValueConsumer getAlgorithmValueConsumer() {
|
||||
argToAvc(this.getAlgorithmArg(), result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to initialize a key.
|
||||
*/
|
||||
abstract class EvpKeyInitializer extends EvpInitializer {
|
||||
abstract Expr getKeyArg();
|
||||
}
|
||||
|
||||
/**
|
||||
* A key initializer may initialize the algorithm and the key size through
|
||||
* the key. Extend any instance of key initializer provide initialization
|
||||
* of the algorithm and key size from the key.
|
||||
*/
|
||||
class EvpInitializerThroughKey extends EvpPrimaryAlgorithmInitializer, EvpKeySizeInitializer,
|
||||
EvpKeyInitializer
|
||||
{
|
||||
Expr arg;
|
||||
CtxPointerSource context;
|
||||
|
||||
EvpInitializerThroughKey() {
|
||||
exists(EvpKeyInitializer keyInit |
|
||||
arg = keyInit.getKeyArg() and this = keyInit and context = keyInit.getContext()
|
||||
)
|
||||
}
|
||||
|
||||
override CtxPointerSource getContext() { result = context }
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result =
|
||||
getSourceKeyCreationInstanceFromArg(this.getKeyArg()).(OpenSslOperation).getAlgorithmArg()
|
||||
}
|
||||
|
||||
override Expr getKeySizeArg() {
|
||||
result = getSourceKeyCreationInstanceFromArg(this.getKeyArg()).getKeySizeConsumer().asExpr()
|
||||
}
|
||||
|
||||
override Expr getKeyArg() { result = arg }
|
||||
}
|
||||
|
||||
/**
|
||||
* A default initializer for any key operation that accepts a key as input.
|
||||
* A key initializer allows for a mechanic to go backwards to the key creation operation
|
||||
* and find the algorithm and key size.
|
||||
* If a user were to stipualte a key consumer for an operation but fail to indicate it as an
|
||||
* initializer, automatic tracing to the creation operation would not occur.
|
||||
* USERS SHOULD NOT NEED TO USE OR EXTEND THIS CLASS DIRECTLY.
|
||||
*
|
||||
* TODO: re-evaluate this approach
|
||||
*/
|
||||
class DefaultKeyInitializer extends EvpKeyInitializer instanceof Crypto::KeyOperationInstance {
|
||||
Expr arg;
|
||||
|
||||
DefaultKeyInitializer() {
|
||||
exists(Call c |
|
||||
c.getAChild*() = arg and
|
||||
arg = this.(Crypto::KeyOperationInstance).getKeyConsumer().asExpr() and
|
||||
c = this
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getKeyArg() { result = arg }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(EvpOperation).getContext() }
|
||||
}
|
||||
|
||||
abstract class EvpIVInitializer extends EvpInitializer {
|
||||
abstract Expr getIVArg();
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to initialize padding.
|
||||
*/
|
||||
abstract class EvpPaddingInitializer extends EvpInitializer {
|
||||
/**
|
||||
* Gets the padding mode argument.
|
||||
* e.g., `EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING)` argument 1 (0-based)
|
||||
*/
|
||||
abstract Expr getPaddingArg();
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to initialize a salt length.
|
||||
*/
|
||||
abstract class EvpSaltLengthInitializer extends EvpInitializer {
|
||||
/**
|
||||
* Gets the salt length argument.
|
||||
* e.g., `EVP_PKEY_CTX_set_scrypt_salt_len(ctx, 16)` argument 1 (0-based)
|
||||
*/
|
||||
abstract Expr getSaltLengthArg();
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to initialize a hash algorithm.
|
||||
*/
|
||||
abstract class EvpHashAlgorithmInitializer extends EvpInitializer {
|
||||
abstract Expr getHashAlgorithmArg();
|
||||
|
||||
Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||
argToAvc(this.getHashAlgorithmArg(), result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to an "update" function.
|
||||
* These are not operations in the sense of Crypto::OperationInstance,
|
||||
* but produce intermediate results for the operation that are later finalized
|
||||
* (see EvpFinal).
|
||||
* Intended for use with EvPOperation.
|
||||
*/
|
||||
abstract class EvpUpdate extends Call {
|
||||
/**
|
||||
* Gets the context argument that ties together initialization, updates and/or final calls.
|
||||
*/
|
||||
abstract CtxPointerSource getContext();
|
||||
|
||||
/**
|
||||
* Update calls always have some input data like plaintext or message digest.
|
||||
*/
|
||||
abstract Expr getInputArg();
|
||||
|
||||
/**
|
||||
* Update calls sometimes have some output data like a plaintext.
|
||||
*/
|
||||
Expr getOutputArg() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The base class for all operations of the EVP API.
|
||||
* This captures one-shot APIs (with and without an initilizer call) and final calls.
|
||||
* Provides some default methods for Crypto::KeyOperationInstance class.
|
||||
*/
|
||||
abstract class EvpOperation extends OpenSslOperation {
|
||||
/**
|
||||
* Gets the context argument that ties together initialization, updates and/or final calls.
|
||||
*/
|
||||
abstract CtxPointerSource getContext();
|
||||
|
||||
/**
|
||||
* Some input data like plaintext or message digest.
|
||||
* Either argument provided direcly in the call or all arguments that were provided in update calls.
|
||||
*/
|
||||
abstract Expr getInputArg();
|
||||
|
||||
/**
|
||||
* Some output data like ciphertext or signature.
|
||||
*/
|
||||
abstract Expr getOutputArg();
|
||||
|
||||
/**
|
||||
* Finds the initialization call, may be none.
|
||||
*/
|
||||
EvpInitializer getInitCall() { ctxSrcToSrcFlow(result.getContext(), this.getContext()) }
|
||||
|
||||
Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
result = DataFlow::exprNode(this.getOutputArg())
|
||||
}
|
||||
|
||||
/**
|
||||
* Input consumer is the input argument of the call.
|
||||
*/
|
||||
Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
result = DataFlow::exprNode(this.getInputArg())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An EVP final call,
|
||||
* which is typicall used in an update/final pattern.
|
||||
* Final operations are typically identified by "final" in the name,
|
||||
* e.g., "EVP_DigestFinal", "EVP_EncryptFinal", etc.
|
||||
* however, this is not a strict rule.
|
||||
*/
|
||||
abstract class EvpFinal extends EvpOperation {
|
||||
/**
|
||||
* All update calls that were executed before this final call.
|
||||
*/
|
||||
EvpUpdate getUpdateCalls() { ctxSrcToSrcFlow(result.getContext(), this.getContext()) }
|
||||
|
||||
/**
|
||||
* Gets the input data provided to all update calls.
|
||||
* If more input data was provided in the final call, override the method.
|
||||
*/
|
||||
override Expr getInputArg() { result = this.getUpdateCalls().getInputArg() }
|
||||
|
||||
/**
|
||||
* Gets the output data provided to all update calls.
|
||||
* If more output data was provided in the final call, override the method.
|
||||
*/
|
||||
override Expr getOutputArg() { result = this.getUpdateCalls().getOutputArg() }
|
||||
Crypto::KeyOperationSubtype resolveKeyOperationSubTypeOperationStep(OperationStep s) {
|
||||
exists(DataFlow::Node src |
|
||||
EncValToInitEncArgFlow::flow(src, s.getInput(KeyOperationSubtypeIO())) and
|
||||
result = intToCipherOperationSubtype(src.asExpr().getValue().toInt())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import OpenSSLOperationBase
|
||||
import EVPCipherOperation
|
||||
import EVPHashOperation
|
||||
import ECKeyGenOperation
|
||||
import EVPSignatureOperation
|
||||
import EVPKeyGenOperation
|
||||
import CipherOperation
|
||||
import HashOperation
|
||||
import SignatureOperation
|
||||
import KeyGenOperation
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* Provides classes for modeling OpenSSL's EVP signature operations
|
||||
*/
|
||||
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AvcFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
||||
|
||||
// TODO: verification functions
|
||||
/**
|
||||
* A base class for final signature operations.
|
||||
*/
|
||||
abstract class EvpSignatureFinalOperation extends OperationStep {
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestSignInit or EVP_DigestSignInit_ex.
|
||||
*/
|
||||
class EvpSignatureDigestInitializer extends OperationStep {
|
||||
EvpSignatureDigestInitializer() {
|
||||
this.getTarget().getName() in ["EVP_DigestSignInit_ex", "EVP_DigestSignInit"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asExpr() = this.getArgument(3) and
|
||||
type = OsslLibContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(2) and type = HashAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit" and
|
||||
result.asExpr() = this.getArgument(4) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asExpr() = this.getArgument(5) and
|
||||
type = KeyIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asExpr() = this.getArgument(6) and
|
||||
type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
// EVP_PKEY_CTX
|
||||
result.asExpr() = this.getArgument(1) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
||||
result.asExpr() = this.getArgument(6) and
|
||||
type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_SignInit or EVP_SignInit_ex.
|
||||
*/
|
||||
class EvpSignInit extends OperationStep {
|
||||
EvpSignInit() { this.getTarget().getName() in ["EVP_SignInit", "EVP_SignInit_ex"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to:
|
||||
* - EVP_PKEY_sign_init_ex
|
||||
* - EVP_PKEY_sign_init_ex2
|
||||
* - EVP_PKEY_sign_init
|
||||
* - EVP_PKEY_sign_message_init
|
||||
*/
|
||||
class EvpPkeySignInit extends OperationStep {
|
||||
EvpPkeySignInit() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_PKEY_sign_init_ex", "EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_init",
|
||||
"EVP_PKEY_sign_message_init"
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
this.getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
|
||||
result.asExpr() = this.getArgument(1) and
|
||||
type = PrimaryAlgorithmIO()
|
||||
or
|
||||
this.getTarget().getName() = "EVP_PKEY_sign_init_ex" and
|
||||
result.asExpr() = this.getArgument(1) and
|
||||
type = OsslParamIO()
|
||||
or
|
||||
// Argument 2 (0 based) only exists for EVP_PKEY_sign_init_ex2 and EVP_PKEY_sign_message_init
|
||||
result.asExpr() = this.getArgument(2) and type = OsslParamIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = InitializerStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DIgestSignUpdate, EVP_SignUpdate or EVP_PKEY_sign_message_update.
|
||||
*/
|
||||
class EvpSignatureUpdateCall extends OperationStep {
|
||||
EvpSignatureUpdateCall() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_DigestSignUpdate", "EVP_SignUpdate", "EVP_PKEY_sign_message_update"
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = UpdateStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_SignFinal or EVP_SignFinal_ex.
|
||||
*/
|
||||
class EvpSignFinal extends EvpSignatureFinalOperation {
|
||||
EvpSignFinal() { this.getTarget().getName() in ["EVP_SignFinal_ex", "EVP_SignFinal"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(3) and type = KeyIO()
|
||||
or
|
||||
// params above 3 (0-based) only exist for EVP_SignFinal_ex
|
||||
result.asExpr() = this.getArgument(4) and
|
||||
type = OsslLibContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestSign or EVP_PKEY_sign.
|
||||
*/
|
||||
class EvpDigestSign extends EvpSignatureFinalOperation {
|
||||
EvpDigestSign() { this.getTarget().getName() in ["EVP_DigestSign", "EVP_PKEY_sign"] }
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to EVP_DigestSignFinal or EVP_PKEY_sign_message_final.
|
||||
*/
|
||||
class EvpDigestAndPkeySignFinal extends EvpSignatureFinalOperation {
|
||||
EvpDigestAndPkeySignFinal() {
|
||||
this.getTarget().getName() in [
|
||||
"EVP_DigestSignFinal",
|
||||
"EVP_PKEY_sign_message_final"
|
||||
]
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutput(IOType type) {
|
||||
result.asExpr() = this.getArgument(0) and type = ContextIO()
|
||||
or
|
||||
result.asExpr() = this.getArgument(1) and type = SignatureIO()
|
||||
}
|
||||
|
||||
override OperationStepType getStepType() { result = FinalStep() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An EVP signature operation instance.
|
||||
*/
|
||||
class EvpSignatureOperationInstance extends Crypto::SignatureOperationInstance instanceof EvpSignatureFinalOperation
|
||||
{
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
super.getPrimaryAlgorithmValueConsumer() = result
|
||||
}
|
||||
|
||||
/**
|
||||
* Signing, verification or unknown.
|
||||
*/
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
// TODO: if this KeyOperationSubtype does not match initialization call's KeyOperationSubtype then we found a bug
|
||||
if super.getTarget().getName().toLowerCase().matches("%sign%")
|
||||
then result instanceof Crypto::TSignMode
|
||||
else
|
||||
if super.getTarget().getName().toLowerCase().matches("%verify%")
|
||||
then result instanceof Crypto::TVerifyMode
|
||||
else result instanceof Crypto::TUnknownKeyOperationMode
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
||||
// TODO: some signing operations may have explicit nonce generators
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys provided in the initialization call or in a context are found by this method.
|
||||
* Keys in explicit arguments are found by overridden methods in extending classes.
|
||||
*/
|
||||
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
||||
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
super.getOutputStepFlowingToStep(SignatureIO()).getOutput(SignatureIO()) = result
|
||||
}
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
||||
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: only signing operations for now, change when verificaiton is added
|
||||
*/
|
||||
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() { none() }
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||
super
|
||||
.getDominatingInitializersToStep(HashAlgorithmIO())
|
||||
.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
||||
}
|
||||
}
|
||||
8
cpp/ql/lib/ext/Oracle.oci.model.yml
Normal file
8
cpp/ql/lib/ext/Oracle.oci.model.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
# partial model of the Oracle Call Interface (OCI) library
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sinkModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
|
||||
- ["", "", False, "OCIStmtPrepare", "", "", "Argument[*2]", "sql-injection", "manual"]
|
||||
- ["", "", False, "OCIStmtPrepare2", "", "", "Argument[*3]", "sql-injection", "manual"]
|
||||
@@ -901,7 +901,7 @@ class BuiltInFunction extends Function {
|
||||
/** Gets a dummy location for the built-in function. */
|
||||
override Location getLocation() {
|
||||
suppressUnusedThis(this) and
|
||||
result instanceof UnknownDefaultLocation
|
||||
result instanceof UnknownLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,9 +53,7 @@ class Location extends @location {
|
||||
predicate fullLocationInfo(
|
||||
Container container, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
locations_default(this, unresolveElement(container), startline, startcolumn, endline, endcolumn) or
|
||||
locations_expr(this, unresolveElement(container), startline, startcolumn, endline, endcolumn) or
|
||||
locations_stmt(this, unresolveElement(container), startline, startcolumn, endline, endcolumn)
|
||||
locations_default(this, unresolveElement(container), startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,30 +144,32 @@ class Locatable extends Element { }
|
||||
* expressions, one for statements and one for other program elements.
|
||||
*/
|
||||
class UnknownLocation extends Location {
|
||||
UnknownLocation() { this.getFile().getAbsolutePath() = "" }
|
||||
UnknownLocation() {
|
||||
this.getFile().getAbsolutePath() = "" and locations_default(this, _, 0, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A dummy location which is used when something doesn't have a location in
|
||||
* the source code but needs to have a `Location` associated with it.
|
||||
*
|
||||
* DEPRECATED: use `UnknownLocation`
|
||||
*/
|
||||
class UnknownDefaultLocation extends UnknownLocation {
|
||||
UnknownDefaultLocation() { locations_default(this, _, 0, 0, 0, 0) }
|
||||
}
|
||||
deprecated class UnknownDefaultLocation extends UnknownLocation { }
|
||||
|
||||
/**
|
||||
* A dummy location which is used when an expression doesn't have a
|
||||
* location in the source code but needs to have a `Location` associated
|
||||
* with it.
|
||||
*
|
||||
* DEPRECATED: use `UnknownLocation`
|
||||
*/
|
||||
class UnknownExprLocation extends UnknownLocation {
|
||||
UnknownExprLocation() { locations_expr(this, _, 0, 0, 0, 0) }
|
||||
}
|
||||
deprecated class UnknownExprLocation extends UnknownLocation { }
|
||||
|
||||
/**
|
||||
* A dummy location which is used when a statement doesn't have a location
|
||||
* in the source code but needs to have a `Location` associated with it.
|
||||
*
|
||||
* DEPRECATED: use `UnknownLocation`
|
||||
*/
|
||||
class UnknownStmtLocation extends UnknownLocation {
|
||||
UnknownStmtLocation() { locations_stmt(this, _, 0, 0, 0, 0) }
|
||||
}
|
||||
deprecated class UnknownStmtLocation extends UnknownLocation { }
|
||||
|
||||
@@ -154,8 +154,9 @@ class MacroInvocation extends MacroAccess {
|
||||
* well.
|
||||
*/
|
||||
Locatable getAnAffectedElement() {
|
||||
inmacroexpansion(unresolveElement(result), underlyingElement(this)) or
|
||||
macrolocationbind(underlyingElement(this), result.getLocation())
|
||||
inmacroexpansion(unresolveElement(result), underlyingElement(this))
|
||||
or
|
||||
macrolocationbind(underlyingElement(this), result.getLocation()) and this != result
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,7 +260,8 @@ predicate inMacroExpansion(Locatable element) {
|
||||
inmacroexpansion(unresolveElement(element), _)
|
||||
or
|
||||
macroLocation(element.getLocation()) and
|
||||
not topLevelMacroAccess(element)
|
||||
not topLevelMacroAccess(element) and
|
||||
not element.getLocation() instanceof UnknownLocation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,7 +40,7 @@ class Namespace extends NameQualifyingElement, @namespace {
|
||||
override Location getLocation() {
|
||||
if strictcount(this.getADeclarationEntry()) = 1
|
||||
then result = this.getADeclarationEntry().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
/** Gets the simple name of this namespace. */
|
||||
|
||||
@@ -13,7 +13,7 @@ class Specifier extends Element, @specifier {
|
||||
/** Gets a dummy location for the specifier. */
|
||||
override Location getLocation() {
|
||||
exists(this) and
|
||||
result instanceof UnknownDefaultLocation
|
||||
result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Specifier" }
|
||||
|
||||
@@ -105,7 +105,7 @@ class AutoType extends TypeTemplateParameter {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AutoType" }
|
||||
|
||||
override Location getLocation() { result instanceof UnknownDefaultLocation }
|
||||
override Location getLocation() { result instanceof UnknownLocation }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -290,7 +290,7 @@ class Type extends Locatable, @type {
|
||||
*/
|
||||
Type stripType() { result = this }
|
||||
|
||||
override Location getLocation() { result instanceof UnknownDefaultLocation }
|
||||
override Location getLocation() { result instanceof UnknownLocation }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -229,6 +229,49 @@ private predicate summaryModel0(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
* This predicate should only be used in tests.
|
||||
*/
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance
|
||||
|
|
||||
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind,
|
||||
provenance, madId)
|
||||
|
|
||||
model =
|
||||
"Source: " + namespace + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; "
|
||||
+ ext + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance
|
||||
|
|
||||
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance,
|
||||
madId)
|
||||
|
|
||||
model =
|
||||
"Sink: " + namespace + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; " +
|
||||
ext + "; " + input + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance
|
||||
|
|
||||
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
|
||||
provenance, madId)
|
||||
|
|
||||
model =
|
||||
"Summary: " + namespace + "; " + type + "; " + subtypes + "; " + name + "; " + signature +
|
||||
"; " + ext + "; " + input + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `input` is `input0`, but with all occurrences of `@` replaced
|
||||
* by `n` repetitions of `*` (and similarly for `output` and `output0`).
|
||||
|
||||
@@ -91,13 +91,13 @@ class Expr extends StmtParent, @expr {
|
||||
*/
|
||||
private Location getExprLocationOverride() {
|
||||
// Base case: the parent has a better location than `this`.
|
||||
this.getDbLocation() instanceof UnknownExprLocation and
|
||||
this.getDbLocation() instanceof UnknownLocation and
|
||||
result = this.getParent().(Expr).getDbLocation() and
|
||||
not result instanceof UnknownLocation
|
||||
or
|
||||
// Recursive case: the parent has a location override that's better than
|
||||
// what `this` has.
|
||||
this.getDbLocation() instanceof UnknownExprLocation and
|
||||
this.getDbLocation() instanceof UnknownLocation and
|
||||
result = this.getParent().(Expr).getExprLocationOverride() and
|
||||
not result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ abstract class InstructionNode0 extends Node0Impl {
|
||||
override Location getLocationImpl() {
|
||||
if exists(instr.getAst().getLocation())
|
||||
then result = instr.getAst().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
final override predicate isGLValue() { exists(getInstructionType(instr, true)) }
|
||||
@@ -227,7 +227,7 @@ abstract class OperandNode0 extends Node0Impl {
|
||||
override Location getLocationImpl() {
|
||||
if exists(op.getDef().getAst().getLocation())
|
||||
then result = op.getDef().getAst().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
final override predicate isGLValue() { exists(getOperandType(op, true)) }
|
||||
|
||||
@@ -847,7 +847,7 @@ class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
|
||||
result = unique( | | p.getLocation())
|
||||
or
|
||||
count(p.getLocation()) != 1 and
|
||||
result instanceof UnknownDefaultLocation
|
||||
result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
final override string toStringImpl() {
|
||||
@@ -1115,7 +1115,7 @@ private module RawIndirectNodes {
|
||||
final override Location getLocationImpl() {
|
||||
if exists(this.getOperand().getLocation())
|
||||
then result = this.getOperand().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
@@ -1161,7 +1161,7 @@ private module RawIndirectNodes {
|
||||
final override Location getLocationImpl() {
|
||||
if exists(this.getInstruction().getLocation())
|
||||
then result = this.getInstruction().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
@@ -1257,7 +1257,7 @@ class FinalParameterNode extends Node, TFinalParameterNode {
|
||||
result = unique( | | p.getLocation())
|
||||
or
|
||||
not exists(unique( | | p.getLocation())) and
|
||||
result instanceof UnknownDefaultLocation
|
||||
result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() { result = stars(this) + p.toString() }
|
||||
@@ -1629,7 +1629,7 @@ class VariableNode extends Node, TGlobalLikeVariableNode {
|
||||
result = unique( | | v.getLocation())
|
||||
or
|
||||
not exists(unique( | | v.getLocation())) and
|
||||
result instanceof UnknownDefaultLocation
|
||||
result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() { result = stars(this) + v.toString() }
|
||||
|
||||
@@ -16,6 +16,7 @@ import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowUtil
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
@@ -95,10 +96,7 @@ module ProductFlow {
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit1() {
|
||||
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
||||
result = 2
|
||||
}
|
||||
default int fieldFlowBranchLimit1() { result = CppDataFlow::defaultFieldFlowBranchLimit() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow in the second
|
||||
@@ -107,10 +105,7 @@ module ProductFlow {
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit2() {
|
||||
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
||||
result = 2
|
||||
}
|
||||
default int fieldFlowBranchLimit2() { result = CppDataFlow::defaultFieldFlowBranchLimit() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,10 +299,7 @@ module ProductFlow {
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit1() {
|
||||
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
||||
result = 2
|
||||
}
|
||||
default int fieldFlowBranchLimit1() { result = CppDataFlow::defaultFieldFlowBranchLimit() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow in the second
|
||||
@@ -316,10 +308,7 @@ module ProductFlow {
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit2() {
|
||||
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
||||
result = 2
|
||||
}
|
||||
default int fieldFlowBranchLimit2() { result = CppDataFlow::defaultFieldFlowBranchLimit() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -516,7 +516,7 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
|
||||
result = unique( | | p.getLocation())
|
||||
or
|
||||
not exists(unique( | | p.getLocation())) and
|
||||
result instanceof UnknownDefaultLocation
|
||||
result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
override BaseIRVariable getBaseSourceVariable() { result.getIRVariable().getAst() = p }
|
||||
|
||||
@@ -45,7 +45,7 @@ module InstructionConsistency {
|
||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||
override string toString() { result = "<Missing IRFunction>" }
|
||||
|
||||
override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation }
|
||||
override Language::Location getLocation() { result instanceof Language::UnknownLocation }
|
||||
}
|
||||
|
||||
private OptionalIRFunction getInstructionIRFunction(Instruction instr) {
|
||||
|
||||
@@ -26,7 +26,7 @@ class ValueNumber extends TValueNumber {
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof Language::UnknownDefaultLocation
|
||||
else result instanceof Language::UnknownLocation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,7 +45,7 @@ module InstructionConsistency {
|
||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||
override string toString() { result = "<Missing IRFunction>" }
|
||||
|
||||
override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation }
|
||||
override Language::Location getLocation() { result instanceof Language::UnknownLocation }
|
||||
}
|
||||
|
||||
private OptionalIRFunction getInstructionIRFunction(Instruction instr) {
|
||||
|
||||
@@ -26,7 +26,7 @@ class ValueNumber extends TValueNumber {
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof Language::UnknownDefaultLocation
|
||||
else result instanceof Language::UnknownLocation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,7 +45,7 @@ module InstructionConsistency {
|
||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||
override string toString() { result = "<Missing IRFunction>" }
|
||||
|
||||
override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation }
|
||||
override Language::Location getLocation() { result instanceof Language::UnknownLocation }
|
||||
}
|
||||
|
||||
private OptionalIRFunction getInstructionIRFunction(Instruction instr) {
|
||||
|
||||
@@ -26,7 +26,7 @@ class ValueNumber extends TValueNumber {
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof Language::UnknownDefaultLocation
|
||||
else result instanceof Language::UnknownLocation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -76,7 +76,7 @@ class GVN extends TValueNumber {
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
final string getKind() {
|
||||
|
||||
@@ -22,8 +22,6 @@ class Location = Cpp::Location;
|
||||
|
||||
class UnknownLocation = Cpp::UnknownLocation;
|
||||
|
||||
class UnknownDefaultLocation = Cpp::UnknownDefaultLocation;
|
||||
|
||||
class File = Cpp::File;
|
||||
|
||||
class AST = Cpp::Locatable;
|
||||
|
||||
@@ -89,7 +89,7 @@ class ZeroBound extends Bound instanceof IRBound::ZeroBound {
|
||||
result = super.getInstruction(delta).getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
override Location getLocation() { result instanceof UnknownDefaultLocation }
|
||||
override Location getLocation() { result instanceof UnknownLocation }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ class ZeroBound extends Bound, TBoundZero {
|
||||
result.(ConstantValueInstruction).getValue().toInt() = delta
|
||||
}
|
||||
|
||||
override Location getLocation() { result instanceof UnknownDefaultLocation }
|
||||
override Location getLocation() { result instanceof UnknownLocation }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -218,10 +218,10 @@ extractor_version(
|
||||
string frontend_version: string ref
|
||||
)
|
||||
|
||||
@location = @location_stmt | @location_expr | @location_default ;
|
||||
@location = @location_default ;
|
||||
|
||||
/**
|
||||
* The location of an element that is not an expression or a statement.
|
||||
* The location of an element.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `file`.
|
||||
* For more information, see
|
||||
@@ -237,40 +237,6 @@ locations_default(
|
||||
int endColumn: int ref
|
||||
);
|
||||
|
||||
/**
|
||||
* The location of a statement.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `file`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
locations_stmt(
|
||||
/** The location of a statement. */
|
||||
unique int id: @location_stmt,
|
||||
int container: @container ref,
|
||||
int startLine: int ref,
|
||||
int startColumn: int ref,
|
||||
int endLine: int ref,
|
||||
int endColumn: int ref
|
||||
);
|
||||
|
||||
/**
|
||||
* The location of an expression.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `file`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
locations_expr(
|
||||
/** The location of an expression. */
|
||||
unique int id: @location_expr,
|
||||
int container: @container ref,
|
||||
int startLine: int ref,
|
||||
int startColumn: int ref,
|
||||
int endLine: int ref,
|
||||
int endColumn: int ref
|
||||
);
|
||||
|
||||
/** An element for which line-count information is available. */
|
||||
@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
|
||||
|
||||
@@ -287,7 +253,7 @@ diagnostics(
|
||||
string error_tag: string ref,
|
||||
string error_message: string ref,
|
||||
string full_error_message: string ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
files(
|
||||
@@ -332,7 +298,7 @@ case @macroinvocation.kind of
|
||||
macroinvocations(
|
||||
unique int id: @macroinvocation,
|
||||
int macro_id: @ppd_define ref,
|
||||
int location: @location_default ref,
|
||||
int location: @location ref,
|
||||
int kind: int ref
|
||||
);
|
||||
|
||||
@@ -453,7 +419,7 @@ fun_decls(
|
||||
int function: @function ref,
|
||||
int type_id: @type ref,
|
||||
string name: string ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
fun_def(unique int id: @fun_decl ref);
|
||||
fun_specialized(unique int id: @fun_decl ref);
|
||||
@@ -505,7 +471,7 @@ var_decls(
|
||||
int variable: @variable ref,
|
||||
int type_id: @type ref,
|
||||
string name: string ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
var_def(unique int id: @var_decl ref);
|
||||
var_specialized(int id: @var_decl ref);
|
||||
@@ -522,7 +488,7 @@ var_requires(
|
||||
type_decls(
|
||||
unique int id: @type_decl,
|
||||
int type_id: @type ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
type_def(unique int id: @type_decl ref);
|
||||
type_decl_top(
|
||||
@@ -536,8 +502,8 @@ type_requires(
|
||||
namespace_decls(
|
||||
unique int id: @namespace_decl,
|
||||
int namespace_id: @namespace ref,
|
||||
int location: @location_default ref,
|
||||
int bodylocation: @location_default ref
|
||||
int location: @location ref,
|
||||
int bodylocation: @location ref
|
||||
);
|
||||
|
||||
case @using.kind of
|
||||
@@ -549,7 +515,7 @@ case @using.kind of
|
||||
usings(
|
||||
unique int id: @using,
|
||||
int element_id: @element ref,
|
||||
int location: @location_default ref,
|
||||
int location: @location ref,
|
||||
int kind: int ref
|
||||
);
|
||||
|
||||
@@ -563,7 +529,7 @@ static_asserts(
|
||||
unique int id: @static_assert,
|
||||
int condition : @expr ref,
|
||||
string message : string ref,
|
||||
int location: @location_default ref,
|
||||
int location: @location ref,
|
||||
int enclosing : @element ref
|
||||
);
|
||||
|
||||
@@ -619,7 +585,7 @@ enumconstants(
|
||||
int index: int ref,
|
||||
int type_id: @type ref,
|
||||
string name: string ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
@variable = @localscopevariable | @globalvariable | @membervariable;
|
||||
@@ -980,7 +946,7 @@ template_template_argument_value(
|
||||
concept_templates(
|
||||
unique int concept_id: @concept_template,
|
||||
string name: string ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
concept_instantiation(
|
||||
unique int to: @concept_id ref,
|
||||
@@ -1084,7 +1050,7 @@ attributes(
|
||||
int kind: int ref,
|
||||
string name: string ref,
|
||||
string name_space: string ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
case @attribute.kind of
|
||||
@@ -1101,7 +1067,7 @@ attribute_args(
|
||||
int kind: int ref,
|
||||
int attribute: @attribute ref,
|
||||
int index: int ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
case @attribute_arg.kind of
|
||||
@@ -1190,7 +1156,7 @@ derivations(
|
||||
int sub: @type ref,
|
||||
int index: int ref,
|
||||
int super: @type ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
derspecifiers(
|
||||
@@ -1224,7 +1190,7 @@ frienddecls(
|
||||
unique int id: @frienddecl,
|
||||
int type_id: @type ref,
|
||||
int decl_id: @declaration ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
@declaredtype = @usertype ;
|
||||
@@ -1281,7 +1247,7 @@ frienddecls(
|
||||
comments(
|
||||
unique int id: @comment,
|
||||
string contents: string ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
commentbinding(
|
||||
@@ -1403,7 +1369,7 @@ namequalifiers(
|
||||
unique int id: @namequalifier,
|
||||
unique int qualifiableelement: @namequalifiableelement ref,
|
||||
int qualifyingelement: @namequalifyingelement ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
varbind(
|
||||
@@ -1672,7 +1638,7 @@ initialisers(
|
||||
unique int init: @initialiser,
|
||||
int var: @accessible ref,
|
||||
unique int expr: @expr ref,
|
||||
int location: @location_expr ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
braced_initialisers(
|
||||
@@ -1691,7 +1657,7 @@ expr_ancestor(
|
||||
exprs(
|
||||
unique int id: @expr,
|
||||
int kind: int ref,
|
||||
int location: @location_expr ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
expr_reuse(
|
||||
@@ -2165,7 +2131,7 @@ lambda_capture(
|
||||
int field: @membervariable ref,
|
||||
boolean captured_by_reference: boolean ref,
|
||||
boolean is_implicit: boolean ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
@funbindexpr = @routineexpr
|
||||
@@ -2193,7 +2159,7 @@ fold(
|
||||
stmts(
|
||||
unique int id: @stmt,
|
||||
int kind: int ref,
|
||||
int location: @location_stmt ref
|
||||
int location: @location ref
|
||||
);
|
||||
|
||||
case @stmt.kind of
|
||||
@@ -2378,7 +2344,7 @@ jumpinfo(
|
||||
preprocdirects(
|
||||
unique int id: @preprocdirect,
|
||||
int kind: int ref,
|
||||
int location: @location_default ref
|
||||
int location: @location ref
|
||||
);
|
||||
case @preprocdirect.kind of
|
||||
0 = @ppd_if
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
class LocationBase = @location_default or @location_stmt or @location_expr;
|
||||
|
||||
class Location extends LocationBase {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Container extends @container {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Location l, Container c, int startLine, int startColumn, int endLine, int endColumn
|
||||
where
|
||||
locations_default(l, c, startLine, startColumn, endLine, endColumn)
|
||||
or
|
||||
locations_stmt(l, c, startLine, startColumn, endLine, endColumn)
|
||||
or
|
||||
locations_expr(l, c, startLine, startColumn, endLine, endColumn)
|
||||
select l, c, startLine, startColumn, endLine, endColumn
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
description: Merge location tables
|
||||
compatibility: full
|
||||
locations_default.rel: run locations_default.qlo
|
||||
locations_expr.rel: delete
|
||||
locations_stmt.rel: delete
|
||||
6
cpp/ql/lib/utils/test/PrettyPrintModels.ql
Normal file
6
cpp/ql/lib/utils/test/PrettyPrintModels.ql
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @kind test-postprocess
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.ExternalFlow
|
||||
import codeql.dataflow.test.ProvenancePathGraph::TestPostProcessing::TranslateProvenanceResults<interpretModelForTest/2>
|
||||
@@ -38,6 +38,9 @@ module SqlTaintedConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(SqlLikeFunction runSql | runSql.outermostWrapperFunctionCall(asSinkExpr(node), _))
|
||||
or
|
||||
// sink defined using models-as-data
|
||||
sinkNode(node, "sql-injection")
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
@@ -56,13 +59,21 @@ module SqlTaintedConfig implements DataFlow::ConfigSig {
|
||||
module SqlTainted = TaintTracking::Global<SqlTaintedConfig>;
|
||||
|
||||
from
|
||||
SqlLikeFunction runSql, Expr taintedArg, FlowSource taintSource, SqlTainted::PathNode sourceNode,
|
||||
SqlTainted::PathNode sinkNode, string callChain
|
||||
Expr taintedArg, FlowSource taintSource, SqlTainted::PathNode sourceNode,
|
||||
SqlTainted::PathNode sinkNode, string extraText
|
||||
where
|
||||
runSql.outermostWrapperFunctionCall(taintedArg, callChain) and
|
||||
(
|
||||
exists(SqlLikeFunction runSql, string callChain |
|
||||
runSql.outermostWrapperFunctionCall(taintedArg, callChain) and
|
||||
extraText = " and then passed to " + callChain
|
||||
)
|
||||
or
|
||||
sinkNode(sinkNode.getNode(), "sql-injection") and
|
||||
extraText = ""
|
||||
) and
|
||||
SqlTainted::flowPath(sourceNode, sinkNode) and
|
||||
taintedArg = asSinkExpr(sinkNode.getNode()) and
|
||||
taintSource = sourceNode.getNode()
|
||||
select taintedArg, sourceNode, sinkNode,
|
||||
"This argument to a SQL query function is derived from $@ and then passed to " + callChain + ".",
|
||||
taintSource, "user input (" + taintSource.getSourceType() + ")"
|
||||
"This argument to a SQL query function is derived from $@" + extraText + ".", taintSource,
|
||||
"user input (" + taintSource.getSourceType() + ")"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `cpp/sql-injection` now can be extended using the `sql-injection` Models as Data (MaD) sink kind.
|
||||
@@ -37,7 +37,7 @@ abstract class MaybePreprocessorDirective extends TMaybePreprocessorDirective {
|
||||
class NoPreprocessorDirective extends TNoPreprocessorDirective, MaybePreprocessorDirective {
|
||||
override string toString() { result = "" }
|
||||
|
||||
override Location getLocation() { result instanceof UnknownDefaultLocation }
|
||||
override Location getLocation() { result instanceof UnknownLocation }
|
||||
}
|
||||
|
||||
class SomePreprocessorDirective extends TSomePreprocessorDirective, MaybePreprocessorDirective {
|
||||
|
||||
@@ -30,9 +30,12 @@
|
||||
| openssl_basic.c:144:13:144:22 | HashOperation | Message | openssl_basic.c:144:24:144:30 | Message |
|
||||
| openssl_basic.c:144:24:144:30 | Message | Source | openssl_basic.c:181:49:181:87 | Constant |
|
||||
| openssl_basic.c:144:46:144:51 | Digest | Source | openssl_basic.c:144:46:144:51 | Digest |
|
||||
| openssl_basic.c:155:22:155:41 | Key | Algorithm | openssl_basic.c:155:22:155:41 | Key |
|
||||
| openssl_basic.c:155:22:155:41 | KeyGeneration | Algorithm | openssl_basic.c:155:22:155:41 | KeyGeneration |
|
||||
| openssl_basic.c:155:22:155:41 | KeyGeneration | KeyInput | openssl_basic.c:155:64:155:66 | Key |
|
||||
| openssl_basic.c:155:22:155:41 | KeyGeneration | Output | openssl_basic.c:155:22:155:41 | Key |
|
||||
| openssl_basic.c:155:43:155:55 | MACAlgorithm | H | openssl_basic.c:160:39:160:48 | HashAlgorithm |
|
||||
| openssl_basic.c:155:64:155:66 | Key | Source | openssl_basic.c:179:43:179:76 | Constant |
|
||||
| openssl_basic.c:160:59:160:62 | Key | Source | openssl_basic.c:155:22:155:41 | Key |
|
||||
| openssl_basic.c:163:35:163:41 | Message | Source | openssl_basic.c:181:49:181:87 | Constant |
|
||||
| openssl_basic.c:167:9:167:27 | SignOperation | Algorithm | openssl_basic.c:167:9:167:27 | SignOperation |
|
||||
@@ -40,8 +43,11 @@
|
||||
| openssl_basic.c:167:9:167:27 | SignOperation | Input | openssl_basic.c:163:35:163:41 | Message |
|
||||
| openssl_basic.c:167:9:167:27 | SignOperation | Key | openssl_basic.c:160:59:160:62 | Key |
|
||||
| openssl_basic.c:167:9:167:27 | SignOperation | Output | openssl_basic.c:167:34:167:36 | SignatureOutput |
|
||||
| openssl_pkey.c:21:10:21:28 | KeyGeneration | Algorithm | openssl_pkey.c:21:10:21:28 | KeyGeneration |
|
||||
| openssl_pkey.c:21:10:21:28 | KeyGeneration | Output | openssl_pkey.c:21:30:21:32 | Key |
|
||||
| openssl_pkey.c:21:10:21:28 | KeyOperationAlgorithm | Mode | openssl_pkey.c:21:10:21:28 | KeyOperationAlgorithm |
|
||||
| openssl_pkey.c:21:10:21:28 | KeyOperationAlgorithm | Padding | openssl_pkey.c:21:10:21:28 | KeyOperationAlgorithm |
|
||||
| openssl_pkey.c:21:30:21:32 | Key | Algorithm | openssl_pkey.c:21:30:21:32 | Key |
|
||||
| openssl_pkey.c:50:31:50:42 | KeyOperationAlgorithm | Mode | openssl_pkey.c:50:31:50:42 | KeyOperationAlgorithm |
|
||||
| openssl_pkey.c:50:31:50:42 | KeyOperationAlgorithm | Padding | openssl_pkey.c:50:31:50:42 | KeyOperationAlgorithm |
|
||||
| openssl_pkey.c:55:9:55:23 | KeyGeneration | Algorithm | openssl_pkey.c:50:31:50:42 | KeyOperationAlgorithm |
|
||||
@@ -77,6 +83,13 @@
|
||||
| openssl_signature.c:133:52:133:55 | Key | Source | openssl_signature.c:548:34:548:37 | Key |
|
||||
| openssl_signature.c:133:52:133:55 | Key | Source | openssl_signature.c:578:34:578:37 | Key |
|
||||
| openssl_signature.c:134:38:134:44 | Message | Source | openssl_signature.c:602:37:602:77 | Constant |
|
||||
| openssl_signature.c:135:9:135:27 | SignOperation | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:135:9:135:27 | SignOperation | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:135:9:135:27 | SignOperation | HashAlgorithm | openssl_signature.c:684:24:684:33 | HashAlgorithm |
|
||||
| openssl_signature.c:135:9:135:27 | SignOperation | HashAlgorithm | openssl_signature.c:740:24:740:33 | HashAlgorithm |
|
||||
| openssl_signature.c:135:9:135:27 | SignOperation | Input | openssl_signature.c:134:38:134:44 | Message |
|
||||
| openssl_signature.c:135:9:135:27 | SignOperation | Key | openssl_signature.c:133:52:133:55 | Key |
|
||||
| openssl_signature.c:135:9:135:27 | SignOperation | Output | openssl_signature.c:135:37:135:40 | SignatureOutput |
|
||||
| openssl_signature.c:142:9:142:27 | SignOperation | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:142:9:142:27 | SignOperation | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:142:9:142:27 | SignOperation | HashAlgorithm | openssl_signature.c:684:24:684:33 | HashAlgorithm |
|
||||
@@ -87,6 +100,13 @@
|
||||
| openssl_signature.c:190:57:190:60 | Key | Source | openssl_signature.c:548:34:548:37 | Key |
|
||||
| openssl_signature.c:190:57:190:60 | Key | Source | openssl_signature.c:578:34:578:37 | Key |
|
||||
| openssl_signature.c:196:38:196:44 | Message | Source | openssl_signature.c:602:37:602:77 | Constant |
|
||||
| openssl_signature.c:197:9:197:27 | SignOperation | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:197:9:197:27 | SignOperation | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:197:9:197:27 | SignOperation | HashAlgorithm | openssl_signature.c:684:24:684:33 | HashAlgorithm |
|
||||
| openssl_signature.c:197:9:197:27 | SignOperation | HashAlgorithm | openssl_signature.c:740:24:740:33 | HashAlgorithm |
|
||||
| openssl_signature.c:197:9:197:27 | SignOperation | Input | openssl_signature.c:196:38:196:44 | Message |
|
||||
| openssl_signature.c:197:9:197:27 | SignOperation | Key | openssl_signature.c:190:57:190:60 | Key |
|
||||
| openssl_signature.c:197:9:197:27 | SignOperation | Output | openssl_signature.c:197:37:197:40 | SignatureOutput |
|
||||
| openssl_signature.c:204:9:204:27 | SignOperation | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:204:9:204:27 | SignOperation | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:204:9:204:27 | SignOperation | HashAlgorithm | openssl_signature.c:684:24:684:33 | HashAlgorithm |
|
||||
@@ -96,6 +116,14 @@
|
||||
| openssl_signature.c:204:9:204:27 | SignOperation | Output | openssl_signature.c:204:37:204:46 | SignatureOutput |
|
||||
| openssl_signature.c:260:39:260:42 | Key | Source | openssl_signature.c:548:34:548:37 | Key |
|
||||
| openssl_signature.c:260:39:260:42 | Key | Source | openssl_signature.c:578:34:578:37 | Key |
|
||||
| openssl_signature.c:263:9:263:21 | SignOperation | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:263:9:263:21 | SignOperation | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:263:9:263:21 | SignOperation | HashAlgorithm | openssl_signature.c:684:24:684:33 | HashAlgorithm |
|
||||
| openssl_signature.c:263:9:263:21 | SignOperation | HashAlgorithm | openssl_signature.c:740:24:740:33 | HashAlgorithm |
|
||||
| openssl_signature.c:263:9:263:21 | SignOperation | Input | openssl_signature.c:263:54:263:59 | Message |
|
||||
| openssl_signature.c:263:9:263:21 | SignOperation | Key | openssl_signature.c:260:39:260:42 | Key |
|
||||
| openssl_signature.c:263:9:263:21 | SignOperation | Output | openssl_signature.c:263:33:263:36 | SignatureOutput |
|
||||
| openssl_signature.c:263:54:263:59 | Message | Source | openssl_signature.c:263:54:263:59 | Message |
|
||||
| openssl_signature.c:270:9:270:21 | SignOperation | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:270:9:270:21 | SignOperation | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:270:9:270:21 | SignOperation | HashAlgorithm | openssl_signature.c:684:24:684:33 | HashAlgorithm |
|
||||
@@ -107,6 +135,14 @@
|
||||
| openssl_signature.c:321:39:321:42 | Key | Source | openssl_signature.c:548:34:548:37 | Key |
|
||||
| openssl_signature.c:321:39:321:42 | Key | Source | openssl_signature.c:578:34:578:37 | Key |
|
||||
| openssl_signature.c:326:48:326:54 | Message | Source | openssl_signature.c:602:37:602:77 | Constant |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation | Algorithm | openssl_signature.c:702:60:702:71 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation | Algorithm | openssl_signature.c:758:60:758:64 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation | HashAlgorithm | openssl_signature.c:327:9:327:35 | SignOperation |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation | Input | openssl_signature.c:326:48:326:54 | Message |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation | Key | openssl_signature.c:321:39:321:42 | Key |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation | Output | openssl_signature.c:327:47:327:50 | SignatureOutput |
|
||||
| openssl_signature.c:334:9:334:35 | SignOperation | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:334:9:334:35 | SignOperation | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:334:9:334:35 | SignOperation | Algorithm | openssl_signature.c:702:60:702:71 | KeyOperationAlgorithm |
|
||||
@@ -120,7 +156,9 @@
|
||||
| openssl_signature.c:548:9:548:23 | KeyGeneration | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:548:9:548:23 | KeyGeneration | Output | openssl_signature.c:548:34:548:37 | Key |
|
||||
| openssl_signature.c:548:34:548:37 | Key | Algorithm | openssl_signature.c:543:35:543:46 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:575:32:575:37 | Key | Source | openssl_signature.c:575:32:575:37 | Key |
|
||||
| openssl_signature.c:578:9:578:23 | KeyGeneration | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:578:9:578:23 | KeyGeneration | KeyInput | openssl_signature.c:575:32:575:37 | Key |
|
||||
| openssl_signature.c:578:9:578:23 | KeyGeneration | Output | openssl_signature.c:578:34:578:37 | Key |
|
||||
| openssl_signature.c:578:34:578:37 | Key | Algorithm | openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:702:60:702:71 | KeyOperationAlgorithm | Padding | openssl_signature.c:702:60:702:71 | KeyOperationAlgorithm |
|
||||
|
||||
@@ -20,9 +20,10 @@
|
||||
| openssl_basic.c:144:67:144:73 | HashAlgorithm | DigestSize | 128 | openssl_basic.c:144:67:144:73 | openssl_basic.c:144:67:144:73 |
|
||||
| openssl_basic.c:144:67:144:73 | HashAlgorithm | Name | MD5 | openssl_basic.c:144:67:144:73 | openssl_basic.c:144:67:144:73 |
|
||||
| openssl_basic.c:144:67:144:73 | HashAlgorithm | RawName | EVP_md5 | openssl_basic.c:144:67:144:73 | openssl_basic.c:144:67:144:73 |
|
||||
| openssl_basic.c:155:22:155:41 | Key | KeyType | Symmetric | openssl_basic.c:155:22:155:41 | openssl_basic.c:155:22:155:41 |
|
||||
| openssl_basic.c:155:22:155:41 | Key | KeyType | Asymmetric | openssl_basic.c:155:22:155:41 | openssl_basic.c:155:22:155:41 |
|
||||
| openssl_basic.c:155:43:155:55 | MACAlgorithm | Name | HMAC | openssl_basic.c:155:43:155:55 | openssl_basic.c:155:43:155:55 |
|
||||
| openssl_basic.c:155:43:155:55 | MACAlgorithm | RawName | 855 | openssl_basic.c:155:43:155:55 | openssl_basic.c:155:43:155:55 |
|
||||
| openssl_basic.c:155:64:155:66 | Key | KeyType | Unknown | openssl_basic.c:155:64:155:66 | openssl_basic.c:155:64:155:66 |
|
||||
| openssl_basic.c:160:39:160:48 | HashAlgorithm | DigestSize | 256 | openssl_basic.c:160:39:160:48 | openssl_basic.c:160:39:160:48 |
|
||||
| openssl_basic.c:160:39:160:48 | HashAlgorithm | Name | SHA2 | openssl_basic.c:160:39:160:48 | openssl_basic.c:160:39:160:48 |
|
||||
| openssl_basic.c:160:39:160:48 | HashAlgorithm | RawName | EVP_sha256 | openssl_basic.c:160:39:160:48 | openssl_basic.c:160:39:160:48 |
|
||||
@@ -34,6 +35,7 @@
|
||||
| openssl_basic.c:218:32:218:33 | Constant | Description | 32 | openssl_basic.c:218:32:218:33 | openssl_basic.c:218:32:218:33 |
|
||||
| openssl_pkey.c:21:10:21:28 | KeyOperationAlgorithm | Name | RSA | openssl_pkey.c:21:10:21:28 | openssl_pkey.c:21:10:21:28 |
|
||||
| openssl_pkey.c:21:10:21:28 | KeyOperationAlgorithm | RawName | RSA_generate_key_ex | openssl_pkey.c:21:10:21:28 | openssl_pkey.c:21:10:21:28 |
|
||||
| openssl_pkey.c:21:30:21:32 | Key | KeyType | Asymmetric | openssl_pkey.c:21:30:21:32 | openssl_pkey.c:21:30:21:32 |
|
||||
| openssl_pkey.c:45:49:45:65 | Constant | Description | Hello, OpenSSL! | openssl_pkey.c:45:49:45:65 | openssl_pkey.c:45:49:45:65 |
|
||||
| openssl_pkey.c:50:31:50:42 | KeyOperationAlgorithm | Name | RSA | openssl_pkey.c:50:31:50:42 | openssl_pkey.c:50:31:50:42 |
|
||||
| openssl_pkey.c:50:31:50:42 | KeyOperationAlgorithm | RawName | 6 | openssl_pkey.c:50:31:50:42 | openssl_pkey.c:50:31:50:42 |
|
||||
@@ -44,12 +46,16 @@
|
||||
| openssl_signature.c:80:9:80:21 | SignOperation | KeyOperationSubtype | Sign | openssl_signature.c:80:9:80:21 | openssl_signature.c:80:9:80:21 |
|
||||
| openssl_signature.c:80:53:80:56 | Key | KeyType | Unknown | openssl_signature.c:80:53:80:56 | openssl_signature.c:80:53:80:56 |
|
||||
| openssl_signature.c:133:52:133:55 | Key | KeyType | Unknown | openssl_signature.c:133:52:133:55 | openssl_signature.c:133:52:133:55 |
|
||||
| openssl_signature.c:135:9:135:27 | SignOperation | KeyOperationSubtype | Sign | openssl_signature.c:135:9:135:27 | openssl_signature.c:135:9:135:27 |
|
||||
| openssl_signature.c:142:9:142:27 | SignOperation | KeyOperationSubtype | Sign | openssl_signature.c:142:9:142:27 | openssl_signature.c:142:9:142:27 |
|
||||
| openssl_signature.c:190:57:190:60 | Key | KeyType | Unknown | openssl_signature.c:190:57:190:60 | openssl_signature.c:190:57:190:60 |
|
||||
| openssl_signature.c:197:9:197:27 | SignOperation | KeyOperationSubtype | Sign | openssl_signature.c:197:9:197:27 | openssl_signature.c:197:9:197:27 |
|
||||
| openssl_signature.c:204:9:204:27 | SignOperation | KeyOperationSubtype | Sign | openssl_signature.c:204:9:204:27 | openssl_signature.c:204:9:204:27 |
|
||||
| openssl_signature.c:260:39:260:42 | Key | KeyType | Unknown | openssl_signature.c:260:39:260:42 | openssl_signature.c:260:39:260:42 |
|
||||
| openssl_signature.c:263:9:263:21 | SignOperation | KeyOperationSubtype | Sign | openssl_signature.c:263:9:263:21 | openssl_signature.c:263:9:263:21 |
|
||||
| openssl_signature.c:270:9:270:21 | SignOperation | KeyOperationSubtype | Sign | openssl_signature.c:270:9:270:21 | openssl_signature.c:270:9:270:21 |
|
||||
| openssl_signature.c:321:39:321:42 | Key | KeyType | Unknown | openssl_signature.c:321:39:321:42 | openssl_signature.c:321:39:321:42 |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation | KeyOperationSubtype | Sign | openssl_signature.c:327:9:327:35 | openssl_signature.c:327:9:327:35 |
|
||||
| openssl_signature.c:334:9:334:35 | SignOperation | KeyOperationSubtype | Sign | openssl_signature.c:334:9:334:35 | openssl_signature.c:334:9:334:35 |
|
||||
| openssl_signature.c:521:46:521:66 | PaddingAlgorithm | Name | PSS | openssl_signature.c:521:46:521:66 | openssl_signature.c:521:46:521:66 |
|
||||
| openssl_signature.c:521:46:521:66 | PaddingAlgorithm | RawName | 6 | openssl_signature.c:521:46:521:66 | openssl_signature.c:521:46:521:66 |
|
||||
@@ -60,6 +66,7 @@
|
||||
| openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm | Name | DSA | openssl_signature.c:565:50:565:54 | openssl_signature.c:565:50:565:54 |
|
||||
| openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm | RawName | dsa | openssl_signature.c:565:50:565:54 | openssl_signature.c:565:50:565:54 |
|
||||
| openssl_signature.c:569:55:569:58 | Constant | Description | 2048 | openssl_signature.c:569:55:569:58 | openssl_signature.c:569:55:569:58 |
|
||||
| openssl_signature.c:575:32:575:37 | Key | KeyType | Unknown | openssl_signature.c:575:32:575:37 | openssl_signature.c:575:32:575:37 |
|
||||
| openssl_signature.c:578:34:578:37 | Key | KeyType | Asymmetric | openssl_signature.c:578:34:578:37 | openssl_signature.c:578:34:578:37 |
|
||||
| openssl_signature.c:602:37:602:77 | Constant | Description | Test message for OpenSSL signature APIs | openssl_signature.c:602:37:602:77 | openssl_signature.c:602:37:602:77 |
|
||||
| openssl_signature.c:684:24:684:33 | HashAlgorithm | DigestSize | 256 | openssl_signature.c:684:24:684:33 | openssl_signature.c:684:24:684:33 |
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
| openssl_basic.c:155:22:155:41 | Key |
|
||||
| openssl_basic.c:155:22:155:41 | KeyGeneration |
|
||||
| openssl_basic.c:155:43:155:55 | MACAlgorithm |
|
||||
| openssl_basic.c:155:64:155:66 | Key |
|
||||
| openssl_basic.c:160:39:160:48 | HashAlgorithm |
|
||||
| openssl_basic.c:160:59:160:62 | Key |
|
||||
| openssl_basic.c:163:35:163:41 | Message |
|
||||
@@ -34,7 +35,9 @@
|
||||
| openssl_basic.c:180:42:180:59 | Constant |
|
||||
| openssl_basic.c:181:49:181:87 | Constant |
|
||||
| openssl_basic.c:218:32:218:33 | Constant |
|
||||
| openssl_pkey.c:21:10:21:28 | KeyGeneration |
|
||||
| openssl_pkey.c:21:10:21:28 | KeyOperationAlgorithm |
|
||||
| openssl_pkey.c:21:30:21:32 | Key |
|
||||
| openssl_pkey.c:45:49:45:65 | Constant |
|
||||
| openssl_pkey.c:50:31:50:42 | KeyOperationAlgorithm |
|
||||
| openssl_pkey.c:54:47:54:50 | Constant |
|
||||
@@ -54,18 +57,27 @@
|
||||
| openssl_signature.c:80:53:80:56 | Key |
|
||||
| openssl_signature.c:133:52:133:55 | Key |
|
||||
| openssl_signature.c:134:38:134:44 | Message |
|
||||
| openssl_signature.c:135:9:135:27 | SignOperation |
|
||||
| openssl_signature.c:135:37:135:40 | SignatureOutput |
|
||||
| openssl_signature.c:142:9:142:27 | SignOperation |
|
||||
| openssl_signature.c:142:37:142:46 | SignatureOutput |
|
||||
| openssl_signature.c:190:57:190:60 | Key |
|
||||
| openssl_signature.c:196:38:196:44 | Message |
|
||||
| openssl_signature.c:197:9:197:27 | SignOperation |
|
||||
| openssl_signature.c:197:37:197:40 | SignatureOutput |
|
||||
| openssl_signature.c:204:9:204:27 | SignOperation |
|
||||
| openssl_signature.c:204:37:204:46 | SignatureOutput |
|
||||
| openssl_signature.c:260:39:260:42 | Key |
|
||||
| openssl_signature.c:263:9:263:21 | SignOperation |
|
||||
| openssl_signature.c:263:33:263:36 | SignatureOutput |
|
||||
| openssl_signature.c:263:54:263:59 | Message |
|
||||
| openssl_signature.c:270:9:270:21 | SignOperation |
|
||||
| openssl_signature.c:270:33:270:42 | SignatureOutput |
|
||||
| openssl_signature.c:270:60:270:65 | Message |
|
||||
| openssl_signature.c:321:39:321:42 | Key |
|
||||
| openssl_signature.c:326:48:326:54 | Message |
|
||||
| openssl_signature.c:327:9:327:35 | SignOperation |
|
||||
| openssl_signature.c:327:47:327:50 | SignatureOutput |
|
||||
| openssl_signature.c:334:9:334:35 | SignOperation |
|
||||
| openssl_signature.c:334:47:334:56 | SignatureOutput |
|
||||
| openssl_signature.c:521:46:521:66 | PaddingAlgorithm |
|
||||
@@ -75,6 +87,7 @@
|
||||
| openssl_signature.c:548:34:548:37 | Key |
|
||||
| openssl_signature.c:565:50:565:54 | KeyOperationAlgorithm |
|
||||
| openssl_signature.c:569:55:569:58 | Constant |
|
||||
| openssl_signature.c:575:32:575:37 | Key |
|
||||
| openssl_signature.c:578:9:578:23 | KeyGeneration |
|
||||
| openssl_signature.c:578:34:578:37 | Key |
|
||||
| openssl_signature.c:602:37:602:77 | Constant |
|
||||
|
||||
@@ -15,5 +15,5 @@ query predicate instructionBounds(
|
||||
not valueNumber(b.getInstruction()) = valueNumber(i) and
|
||||
if reason instanceof CondReason
|
||||
then reasonLoc = reason.(CondReason).getCond().getLocation()
|
||||
else reasonLoc instanceof UnknownDefaultLocation
|
||||
else reasonLoc instanceof UnknownLocation
|
||||
}
|
||||
|
||||
@@ -1,57 +1,80 @@
|
||||
testFailures
|
||||
models
|
||||
| 1 | Sink: ; ; false; ymlSink; ; ; Argument[0]; test-sink; manual |
|
||||
| 2 | Sink: boost::asio; ; false; write; ; ; Argument[*1]; remote-sink; manual |
|
||||
| 3 | Source: ; ; false; GetCommandLineA; ; ; ReturnValue[*]; local; manual |
|
||||
| 4 | Source: ; ; false; GetEnvironmentStringsA; ; ; ReturnValue[*]; local; manual |
|
||||
| 5 | Source: ; ; false; GetEnvironmentVariableA; ; ; Argument[*1]; local; manual |
|
||||
| 6 | Source: ; ; false; MapViewOfFile2; ; ; ReturnValue[*]; local; manual |
|
||||
| 7 | Source: ; ; false; MapViewOfFile3; ; ; ReturnValue[*]; local; manual |
|
||||
| 8 | Source: ; ; false; MapViewOfFile3FromApp; ; ; ReturnValue[*]; local; manual |
|
||||
| 9 | Source: ; ; false; MapViewOfFile; ; ; ReturnValue[*]; local; manual |
|
||||
| 10 | Source: ; ; false; MapViewOfFileEx; ; ; ReturnValue[*]; local; manual |
|
||||
| 11 | Source: ; ; false; MapViewOfFileFromApp; ; ; ReturnValue[*]; local; manual |
|
||||
| 12 | Source: ; ; false; MapViewOfFileNuma2; ; ; ReturnValue[*]; local; manual |
|
||||
| 13 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual |
|
||||
| 14 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual |
|
||||
| 15 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual |
|
||||
| 16 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual |
|
||||
| 17 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual |
|
||||
| 18 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual |
|
||||
| 19 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual |
|
||||
| 20 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
|
||||
| 21 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 22 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 23 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
|
||||
edges
|
||||
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:10 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:2 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:2 Sink:MaD:6 |
|
||||
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:23 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:17 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:17 Sink:MaD:2 |
|
||||
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
|
||||
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:10 |
|
||||
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:26955 |
|
||||
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:26956 |
|
||||
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:26957 |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:23 |
|
||||
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:21 |
|
||||
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:20 |
|
||||
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:22 |
|
||||
| test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | |
|
||||
| test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:26953 |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:26954 |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:16 |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:1 |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:25:35:25:35 | x | provenance | |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | |
|
||||
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | |
|
||||
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:26954 |
|
||||
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | provenance | |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:26955 |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:21 |
|
||||
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | |
|
||||
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:26954 |
|
||||
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | provenance | |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:26956 |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:20 |
|
||||
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | |
|
||||
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:26954 |
|
||||
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | provenance | |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:26957 |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:22 |
|
||||
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | |
|
||||
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:26954 |
|
||||
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 |
|
||||
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | |
|
||||
| test.cpp:32:41:32:41 | x | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | |
|
||||
| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:341 |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:325 |
|
||||
| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:18 |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:24:8:24:11 | * ... | provenance | |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | |
|
||||
| windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | |
|
||||
| windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | provenance | |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:341 |
|
||||
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:327 |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:18 |
|
||||
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 |
|
||||
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | |
|
||||
| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:329 |
|
||||
| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 |
|
||||
| windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [*hEvent] | windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | provenance | |
|
||||
| windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [hEvent] | windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | provenance | |
|
||||
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | provenance | MaD:343 |
|
||||
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[hEvent] in ReadFileEx | provenance | MaD:343 |
|
||||
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | provenance | MaD:19 |
|
||||
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[hEvent] in ReadFileEx | provenance | MaD:19 |
|
||||
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | |
|
||||
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | |
|
||||
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [*hEvent] | provenance | |
|
||||
@@ -67,36 +90,36 @@ edges
|
||||
| windows.cpp:159:12:159:55 | hEvent | windows.cpp:160:8:160:8 | c | provenance | |
|
||||
| windows.cpp:159:35:159:46 | *lpOverlapped [hEvent] | windows.cpp:159:12:159:55 | hEvent | provenance | |
|
||||
| windows.cpp:159:35:159:46 | *lpOverlapped [hEvent] | windows.cpp:159:12:159:55 | hEvent | provenance | |
|
||||
| windows.cpp:168:35:168:40 | ReadFile output argument | windows.cpp:170:10:170:16 | * ... | provenance | Src:MaD:331 |
|
||||
| windows.cpp:177:23:177:28 | ReadFileEx output argument | windows.cpp:179:10:179:16 | * ... | provenance | Src:MaD:332 |
|
||||
| windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:331 |
|
||||
| windows.cpp:168:35:168:40 | ReadFile output argument | windows.cpp:170:10:170:16 | * ... | provenance | Src:MaD:14 |
|
||||
| windows.cpp:177:23:177:28 | ReadFileEx output argument | windows.cpp:179:10:179:16 | * ... | provenance | Src:MaD:15 |
|
||||
| windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:14 |
|
||||
| windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | windows.cpp:192:53:192:63 | *& ... [*hEvent] | provenance | |
|
||||
| windows.cpp:190:5:190:56 | *... = ... | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | provenance | |
|
||||
| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [*hEvent] | provenance | |
|
||||
| windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:331 |
|
||||
| windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:14 |
|
||||
| windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | windows.cpp:201:53:201:63 | *& ... [hEvent] | provenance | |
|
||||
| windows.cpp:199:5:199:57 | ... = ... | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | provenance | |
|
||||
| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [hEvent] | provenance | |
|
||||
| windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:340 |
|
||||
| windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:333 |
|
||||
| windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:13 |
|
||||
| windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:9 |
|
||||
| windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:287:20:287:52 | *pMapView | provenance | |
|
||||
| windows.cpp:287:20:287:52 | *pMapView | windows.cpp:289:10:289:16 | * ... | provenance | |
|
||||
| windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | provenance | Src:MaD:334 |
|
||||
| windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | provenance | Src:MaD:6 |
|
||||
| windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | windows.cpp:294:20:294:52 | *pMapView | provenance | |
|
||||
| windows.cpp:294:20:294:52 | *pMapView | windows.cpp:296:10:296:16 | * ... | provenance | |
|
||||
| windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | provenance | Src:MaD:335 |
|
||||
| windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | provenance | Src:MaD:7 |
|
||||
| windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | windows.cpp:303:20:303:52 | *pMapView | provenance | |
|
||||
| windows.cpp:303:20:303:52 | *pMapView | windows.cpp:305:10:305:16 | * ... | provenance | |
|
||||
| windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | provenance | Src:MaD:336 |
|
||||
| windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | provenance | Src:MaD:8 |
|
||||
| windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | windows.cpp:312:20:312:52 | *pMapView | provenance | |
|
||||
| windows.cpp:312:20:312:52 | *pMapView | windows.cpp:314:10:314:16 | * ... | provenance | |
|
||||
| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | provenance | Src:MaD:337 |
|
||||
| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | provenance | Src:MaD:10 |
|
||||
| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | windows.cpp:319:20:319:52 | *pMapView | provenance | |
|
||||
| windows.cpp:319:20:319:52 | *pMapView | windows.cpp:321:10:321:16 | * ... | provenance | |
|
||||
| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | provenance | Src:MaD:338 |
|
||||
| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | provenance | Src:MaD:11 |
|
||||
| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | windows.cpp:326:20:326:52 | *pMapView | provenance | |
|
||||
| windows.cpp:326:20:326:52 | *pMapView | windows.cpp:328:10:328:16 | * ... | provenance | |
|
||||
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | provenance | Src:MaD:339 |
|
||||
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | provenance | Src:MaD:12 |
|
||||
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:333:20:333:52 | *pMapView | provenance | |
|
||||
| windows.cpp:333:20:333:52 | *pMapView | windows.cpp:335:10:335:16 | * ... | provenance | |
|
||||
nodes
|
||||
@@ -222,3 +245,4 @@ subpaths
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body |
|
||||
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA |
|
||||
testFailures
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import utils.test.dataflow.FlowTestCommon
|
||||
import cpp
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import IRTest::IRFlow::PathGraph
|
||||
import codeql.dataflow.test.ProvenancePathGraph
|
||||
|
||||
module IRTest {
|
||||
private import semmle.code.cpp.ir.IR
|
||||
@@ -33,3 +33,4 @@ module IRTest {
|
||||
}
|
||||
|
||||
import MakeTest<IRFlowTest<IRTest::IRFlow>>
|
||||
import ShowProvenance<interpretModelForTest/2, IRTest::IRFlow::PathNode, IRTest::IRFlow::PathGraph>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
| bar.h:0:0:0:0 | bar.h:0:0:0:0 |
|
||||
| file://:0:0:0:0 | file://:0:0:0:0 |
|
||||
| file://:0:0:0:0 | file://:0:0:0:0 |
|
||||
| file://:0:0:0:0 | file://:0:0:0:0 |
|
||||
| includes.c:0:0:0:0 | includes.c:0:0:0:0 |
|
||||
| includes.c:2:1:2:15 | includes.c:2:1:2:15 |
|
||||
| includes.c:4:1:4:16 | includes.c:4:1:4:16 |
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
| test.cpp:4:1:4:1 | operator= | false |
|
||||
| test.cpp:4:1:4:1 | operator= | false |
|
||||
| test.cpp:4:1:4:10 | CLASS_DECL | false |
|
||||
| test.cpp:4:1:4:10 | S | false |
|
||||
| test.cpp:4:1:4:10 | S | true |
|
||||
| test.cpp:4:1:4:10 | declaration | true |
|
||||
| test.cpp:4:1:4:10 | definition of S | true |
|
||||
| test.cpp:4:1:4:10 | definition of f | true |
|
||||
| test.cpp:4:1:4:10 | definition of i | true |
|
||||
| test.cpp:4:1:4:10 | definition of j | true |
|
||||
| test.cpp:4:1:4:10 | f | false |
|
||||
| test.cpp:4:1:4:10 | i | false |
|
||||
| test.cpp:4:1:4:10 | f | true |
|
||||
| test.cpp:4:1:4:10 | i | true |
|
||||
| test.cpp:4:1:4:10 | j | true |
|
||||
| test.cpp:4:1:4:10 | return ... | true |
|
||||
| test.cpp:4:1:4:10 | { ... } | true |
|
||||
@@ -30,7 +30,7 @@
|
||||
| test.cpp:8:1:8:13 | declaration | true |
|
||||
| test.cpp:8:1:8:13 | definition of f1 | true |
|
||||
| test.cpp:8:1:8:13 | definition of k | true |
|
||||
| test.cpp:8:1:8:13 | f1 | false |
|
||||
| test.cpp:8:1:8:13 | f1 | true |
|
||||
| test.cpp:8:1:8:13 | k | true |
|
||||
| test.cpp:8:1:8:13 | return ... | true |
|
||||
| test.cpp:8:1:8:13 | { ... } | true |
|
||||
@@ -68,18 +68,18 @@
|
||||
| test.cpp:38:1:38:13 | 1 | true |
|
||||
| test.cpp:38:1:38:13 | ... == ... | true |
|
||||
| test.cpp:38:1:38:13 | STATIC_ASSERT | false |
|
||||
| test.cpp:38:1:38:13 | static_assert(..., "") | false |
|
||||
| test.cpp:38:1:38:13 | static_assert(..., "") | true |
|
||||
| test.cpp:40:1:40:42 | #define ATTRIBUTE [[nodiscard("reason1")]] | false |
|
||||
| test.cpp:42:1:42:9 | ATTRIBUTE | false |
|
||||
| test.cpp:42:1:42:9 | nodiscard | false |
|
||||
| test.cpp:42:1:42:9 | reason1 | false |
|
||||
| test.cpp:42:1:42:9 | nodiscard | true |
|
||||
| test.cpp:42:1:42:9 | reason1 | true |
|
||||
| test.cpp:42:1:42:9 | reason1 | true |
|
||||
| test.cpp:43:5:43:6 | declaration of f2 | false |
|
||||
| test.cpp:43:5:43:6 | f2 | false |
|
||||
| test.cpp:45:1:45:31 | #define ATTRIBUTE_ARG "reason2" | false |
|
||||
| test.cpp:47:3:47:11 | nodiscard | false |
|
||||
| test.cpp:47:13:47:25 | ATTRIBUTE_ARG | false |
|
||||
| test.cpp:47:13:47:25 | reason2 | false |
|
||||
| test.cpp:47:13:47:25 | reason2 | true |
|
||||
| test.cpp:47:13:47:25 | reason2 | true |
|
||||
| test.cpp:48:5:48:6 | declaration of f3 | false |
|
||||
| test.cpp:48:5:48:6 | f3 | false |
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
#select
|
||||
| test.c:21:18:21:23 | query1 | test.c:14:27:14:30 | **argv | test.c:21:18:21:23 | *query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:14:27:14:30 | **argv | user input (a command-line argument) |
|
||||
| test.c:51:18:51:23 | query1 | test.c:14:27:14:30 | **argv | test.c:51:18:51:23 | *query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:14:27:14:30 | **argv | user input (a command-line argument) |
|
||||
| test.c:76:17:76:25 | userInput | test.c:75:8:75:16 | gets output argument | test.c:76:17:76:25 | *userInput | This argument to a SQL query function is derived from $@ and then passed to SQLPrepare(StatementText). | test.c:75:8:75:16 | gets output argument | user input (string read by gets) |
|
||||
| test.c:77:20:77:28 | userInput | test.c:75:8:75:16 | gets output argument | test.c:77:20:77:28 | *userInput | This argument to a SQL query function is derived from $@ and then passed to SQLExecDirect(StatementText). | test.c:75:8:75:16 | gets output argument | user input (string read by gets) |
|
||||
| test.c:106:24:106:29 | query1 | test.c:101:8:101:16 | gets output argument | test.c:106:24:106:29 | *query1 | This argument to a SQL query function is derived from $@. | test.c:101:8:101:16 | gets output argument | user input (string read by gets) |
|
||||
| test.c:107:28:107:33 | query1 | test.c:101:8:101:16 | gets output argument | test.c:107:28:107:33 | *query1 | This argument to a SQL query function is derived from $@. | test.c:101:8:101:16 | gets output argument | user input (string read by gets) |
|
||||
| test.cpp:43:27:43:33 | access to array | test.cpp:39:27:39:30 | **argv | test.cpp:43:27:43:33 | *access to array | This argument to a SQL query function is derived from $@ and then passed to pqxx::work::exec1((unnamed parameter 0)). | test.cpp:39:27:39:30 | **argv | user input (a command-line argument) |
|
||||
edges
|
||||
| test.c:14:27:14:30 | **argv | test.c:15:20:15:26 | *access to array | provenance | |
|
||||
| test.c:15:20:15:26 | *access to array | test.c:21:18:21:23 | *query1 | provenance | TaintFunction |
|
||||
@@ -9,7 +17,12 @@ edges
|
||||
| test.c:48:20:48:33 | *globalUsername | test.c:51:18:51:23 | *query1 | provenance | TaintFunction |
|
||||
| test.c:75:8:75:16 | gets output argument | test.c:76:17:76:25 | *userInput | provenance | |
|
||||
| test.c:75:8:75:16 | gets output argument | test.c:77:20:77:28 | *userInput | provenance | |
|
||||
| test.c:101:8:101:16 | gets output argument | test.c:106:24:106:29 | *query1 | provenance | TaintFunction Sink:MaD:2 |
|
||||
| test.c:101:8:101:16 | gets output argument | test.c:107:28:107:33 | *query1 | provenance | TaintFunction Sink:MaD:1 |
|
||||
| test.cpp:39:27:39:30 | **argv | test.cpp:43:27:43:33 | *access to array | provenance | |
|
||||
models
|
||||
| 1 | Sink: ; ; false; OCIStmtPrepare2; ; ; Argument[*3]; sql-injection; manual |
|
||||
| 2 | Sink: ; ; false; OCIStmtPrepare; ; ; Argument[*2]; sql-injection; manual |
|
||||
nodes
|
||||
| test.c:14:27:14:30 | **argv | semmle.label | **argv |
|
||||
| test.c:15:20:15:26 | *access to array | semmle.label | *access to array |
|
||||
@@ -23,12 +36,9 @@ nodes
|
||||
| test.c:75:8:75:16 | gets output argument | semmle.label | gets output argument |
|
||||
| test.c:76:17:76:25 | *userInput | semmle.label | *userInput |
|
||||
| test.c:77:20:77:28 | *userInput | semmle.label | *userInput |
|
||||
| test.c:101:8:101:16 | gets output argument | semmle.label | gets output argument |
|
||||
| test.c:106:24:106:29 | *query1 | semmle.label | *query1 |
|
||||
| test.c:107:28:107:33 | *query1 | semmle.label | *query1 |
|
||||
| test.cpp:39:27:39:30 | **argv | semmle.label | **argv |
|
||||
| test.cpp:43:27:43:33 | *access to array | semmle.label | *access to array |
|
||||
subpaths
|
||||
#select
|
||||
| test.c:21:18:21:23 | query1 | test.c:14:27:14:30 | **argv | test.c:21:18:21:23 | *query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:14:27:14:30 | **argv | user input (a command-line argument) |
|
||||
| test.c:51:18:51:23 | query1 | test.c:14:27:14:30 | **argv | test.c:51:18:51:23 | *query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:14:27:14:30 | **argv | user input (a command-line argument) |
|
||||
| test.c:76:17:76:25 | userInput | test.c:75:8:75:16 | gets output argument | test.c:76:17:76:25 | *userInput | This argument to a SQL query function is derived from $@ and then passed to SQLPrepare(StatementText). | test.c:75:8:75:16 | gets output argument | user input (string read by gets) |
|
||||
| test.c:77:20:77:28 | userInput | test.c:75:8:75:16 | gets output argument | test.c:77:20:77:28 | *userInput | This argument to a SQL query function is derived from $@ and then passed to SQLExecDirect(StatementText). | test.c:75:8:75:16 | gets output argument | user input (string read by gets) |
|
||||
| test.cpp:43:27:43:33 | access to array | test.cpp:39:27:39:30 | **argv | test.cpp:43:27:43:33 | *access to array | This argument to a SQL query function is derived from $@ and then passed to pqxx::work::exec1((unnamed parameter 0)). | test.cpp:39:27:39:30 | **argv | user input (a command-line argument) |
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
Security/CWE/CWE-089/SqlTainted.ql
|
||||
query: Security/CWE/CWE-089/SqlTainted.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -11,14 +11,14 @@ int atoi(const char *nptr);
|
||||
void exit(int i);
|
||||
///// Test code /////
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main(int argc, char** argv) { // $ Source
|
||||
char *userName = argv[2];
|
||||
int userNumber = atoi(argv[3]);
|
||||
|
||||
// a string from the user is injected directly into an SQL query.
|
||||
char query1[1000] = {0};
|
||||
snprintf(query1, 1000, "SELECT UID FROM USERS where name = \"%s\"", userName);
|
||||
mysql_query(0, query1); // BAD
|
||||
mysql_query(0, query1); // $ Alert
|
||||
|
||||
// the user string is encoded by a library routine.
|
||||
char userNameSanitized[1000] = {0};
|
||||
@@ -48,7 +48,7 @@ void badFunc() {
|
||||
char *userName = globalUsername;
|
||||
char query1[1000] = {0};
|
||||
snprintf(query1, 1000, "SELECT UID FROM USERS where name = \"%s\"", userName);
|
||||
mysql_query(0, query1); // BAD
|
||||
mysql_query(0, query1); // $ Alert
|
||||
}
|
||||
|
||||
//ODBC Library Rountines
|
||||
@@ -72,7 +72,44 @@ SQLRETURN SQLPrepare(
|
||||
|
||||
void ODBCTests(){
|
||||
char userInput[100];
|
||||
gets(userInput);
|
||||
SQLPrepare(0, userInput, 100); // BAD
|
||||
SQLExecDirect(0, userInput, 100); // BAD
|
||||
gets(userInput); // $ Source
|
||||
SQLPrepare(0, userInput, 100); // $ Alert
|
||||
SQLExecDirect(0, userInput, 100); // $ Alert
|
||||
}
|
||||
|
||||
// Oracle Call Interface (OCI) Routines
|
||||
int OCIStmtPrepare(
|
||||
void *arg0,
|
||||
void *arg1,
|
||||
const unsigned char *sql,
|
||||
unsigned int arg3,
|
||||
unsigned int arg4,
|
||||
unsigned int arg5);
|
||||
int OCIStmtPrepare2(
|
||||
void *arg0,
|
||||
void **arg1,
|
||||
void *arg2,
|
||||
const unsigned char *sql,
|
||||
unsigned int arg4,
|
||||
const unsigned char *arg5,
|
||||
unsigned int arg6,
|
||||
unsigned int arg7,
|
||||
unsigned int arg8);
|
||||
|
||||
void OCITests(){
|
||||
char userInput[100];
|
||||
gets(userInput); // $ Source
|
||||
|
||||
// a string from the user is injected directly into an SQL query.
|
||||
char query1[1000] = {0};
|
||||
snprintf(query1, 1000, "SELECT UID FROM USERS where name = \"%s\"", userInput);
|
||||
OCIStmtPrepare(0, 0, query1, 0, 0, 0); // $ Alert
|
||||
OCIStmtPrepare2(0, 0, 0, query1, 0, 0, 0, 0, 0); // $ Alert
|
||||
|
||||
// an integer from the user is injected into an SQL query.
|
||||
int userNumber = atoi(userInput);
|
||||
char query2[1000] = {0};
|
||||
snprintf(query2, 1000, "SELECT UID FROM USERS where number = \"%i\"", userNumber);
|
||||
OCIStmtPrepare(0, 0, query2, 0, 0, 0); // GOOD
|
||||
OCIStmtPrepare2(0, 0, 0, query2, 0, 0, 0, 0, 0); // GOOD
|
||||
}
|
||||
@@ -36,11 +36,11 @@ namespace pqxx {
|
||||
};
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main(int argc, char** argv) { // $ Source
|
||||
pqxx::connection c;
|
||||
pqxx::work w(c);
|
||||
|
||||
pqxx::row r = w.exec1(argv[1]); // BAD
|
||||
pqxx::row r = w.exec1(argv[1]); // $ Alert
|
||||
|
||||
pqxx::result r2 = w.exec(w.quote(argv[1])); // GOOD
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ Microsoft.AspNetCore.Http,,,1,,,,,,,,,,,,,,,,,,,1,
|
||||
Microsoft.AspNetCore.Mvc,,,2,,,,,,,,,,,,,,,,,,,,2
|
||||
Microsoft.AspNetCore.WebUtilities,,,2,,,,,,,,,,,,,,,,,,,2,
|
||||
Microsoft.CSharp,,,2,,,,,,,,,,,,,,,,,,,2,
|
||||
Microsoft.Data.SqlClient,7,,4,,,,,,,,,,7,,,,,,,,,4,
|
||||
Microsoft.Diagnostics.Tools.Pgo,,,21,,,,,,,,,,,,,,,,,,,,21
|
||||
Microsoft.DotNet.Build.Tasks,,,11,,,,,,,,,,,,,,,,,,,9,2
|
||||
Microsoft.DotNet.PlatformAbstractions,,,1,,,,,,,,,,,,,,,,,,,1,
|
||||
|
||||
|
@@ -9,6 +9,6 @@ C# framework & library support
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",47,12139,54,5
|
||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.AspNetCore.Components``, ``Microsoft.AspNetCore.Http``, ``Microsoft.AspNetCore.Mvc``, ``Microsoft.AspNetCore.WebUtilities``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",60,2253,152,4
|
||||
Totals,,107,14399,400,9
|
||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.AspNetCore.Components``, ``Microsoft.AspNetCore.Http``, ``Microsoft.AspNetCore.Mvc``, ``Microsoft.AspNetCore.WebUtilities``, ``Microsoft.CSharp``, ``Microsoft.Data.SqlClient``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",60,2257,159,4
|
||||
Totals,,107,14403,407,9
|
||||
|
||||
|
||||
20
csharp/ql/lib/ext/Microsoft.Data.SqlClient.model.yml
Normal file
20
csharp/ql/lib/ext/Microsoft.Data.SqlClient.model.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["Microsoft.Data.SqlClient", "SqlCommand", False, "SqlCommand", "(System.String)", "", "Argument[0]", "sql-injection", "manual"]
|
||||
- ["Microsoft.Data.SqlClient", "SqlCommand", False, "SqlCommand", "(System.String,Microsoft.Data.SqlClient.SqlConnection)", "", "Argument[0]", "sql-injection", "manual"]
|
||||
- ["Microsoft.Data.SqlClient", "SqlCommand", False, "SqlCommand", "(System.String,Microsoft.Data.SqlClient.SqlConnection,Microsoft.Data.SqlClient.SqlTransaction)", "", "Argument[0]", "sql-injection", "manual"]
|
||||
- ["Microsoft.Data.SqlClient", "SqlCommand", False, "SqlCommand", "(System.String,Microsoft.Data.SqlClient.SqlConnection,Microsoft.Data.SqlClient.SqlTransaction,Microsoft.Data.SqlClient.SqlCommandColumnEncryptionSetting)", "", "Argument[0]", "sql-injection", "manual"]
|
||||
- ["Microsoft.Data.SqlClient", "SqlDataAdapter", False, "SqlDataAdapter", "(Microsoft.Data.SqlClient.SqlCommand)", "", "Argument[0]", "sql-injection", "manual"]
|
||||
- ["Microsoft.Data.SqlClient", "SqlDataAdapter", False, "SqlDataAdapter", "(System.String,Microsoft.Data.SqlClient.SqlConnection)", "", "Argument[0]", "sql-injection", "manual"]
|
||||
- ["Microsoft.Data.SqlClient", "SqlDataAdapter", False, "SqlDataAdapter", "(System.String,System.String)", "", "Argument[0]", "sql-injection", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["Microsoft.Data.SqlClient", "SqlCommand", False, "SqlCommand", "(System.String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||
- ["Microsoft.Data.SqlClient", "SqlCommand", False, "SqlCommand", "(System.String,Microsoft.Data.SqlClient.SqlConnection)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||
- ["Microsoft.Data.SqlClient", "SqlCommand", False, "SqlCommand", "(System.String,Microsoft.Data.SqlClient.SqlConnection,Microsoft.Data.SqlClient.SqlTransaction)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||
- ["Microsoft.Data.SqlClient", "SqlCommand", False, "SqlCommand", "(System.String,Microsoft.Data.SqlClient.SqlConnection,Microsoft.Data.SqlClient.SqlTransaction,Microsoft.Data.SqlClient.SqlCommandColumnEncryptionSetting)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for representing abstract bounds for use in, for example, range analysis.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import internal.rangeanalysis.BoundSpecific
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* an expression, `b` is a `Bound` (typically zero or the value of an SSA
|
||||
* variable), and `v` is an integer in the range `[0 .. m-1]`.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import internal.rangeanalysis.ModulusAnalysisSpecific::Private
|
||||
private import Bound
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
newtype TSign =
|
||||
TNeg() or
|
||||
TZero() or
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* The analysis is implemented as an abstract interpretation over the
|
||||
* three-valued domain `{negative, zero, positive}`.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import SignAnalysisSpecific::Private
|
||||
private import SsaReadPositionCommon
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for representing a position at which an SSA variable is read.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import SsaReadPositionSpecific
|
||||
import SsaReadPositionSpecific::Public
|
||||
|
||||
@@ -35,6 +35,7 @@ class IDbCommandConstructionSqlExpr extends SqlExpr, ObjectCreation {
|
||||
ic.getParameter(0).getType() instanceof StringType and
|
||||
not exists(Type t | t = ic.getDeclaringType() |
|
||||
// Known sealed classes:
|
||||
t.hasFullyQualifiedName("Microsoft.Data.SqlClient", "SqlCommand") or
|
||||
t.hasFullyQualifiedName("System.Data.SqlClient", "SqlCommand") or
|
||||
t.hasFullyQualifiedName("System.Data.Odbc", "OdbcCommand") or
|
||||
t.hasFullyQualifiedName("System.Data.OleDb", "OleDbCommand") or
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added explicit SQL injection Models as Data models for `Microsoft.Data.SqlClient.SqlCommand` and `Microsoft.Data.SqlClient.SqlDataAdapter`. This reduces false negatives for the query `cs/sql-injection`.
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Microsoft.Data;
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace Test
|
||||
{
|
||||
class SqlInjection
|
||||
{
|
||||
string connectionString;
|
||||
System.Windows.Forms.TextBox box1;
|
||||
|
||||
public void MakeSqlCommand()
|
||||
{
|
||||
// BAD: Text from a local textbox
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var queryString = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
var cmd = new SqlCommand(queryString); // $ Alert[cs/sql-injection]
|
||||
var adapter = new SqlDataAdapter(cmd); // $ Alert[cs/sql-injection]
|
||||
}
|
||||
|
||||
// BAD: Input from the command line.
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var queryString = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ Console.ReadLine() + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
var cmd = new SqlCommand(queryString); // $ Alert[cs/sql-injection]
|
||||
var adapter = new SqlDataAdapter(cmd); // $ Alert[cs/sql-injection]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#select
|
||||
| SqlInjection.cs:19:42:19:52 | access to local variable queryString | SqlInjection.cs:18:21:18:29 | access to property Text : String | SqlInjection.cs:19:42:19:52 | access to local variable queryString | This query depends on $@. | SqlInjection.cs:18:21:18:29 | access to property Text : String | this TextBox text |
|
||||
| SqlInjection.cs:20:50:20:52 | access to local variable cmd | SqlInjection.cs:18:21:18:29 | access to property Text : String | SqlInjection.cs:20:50:20:52 | access to local variable cmd | This query depends on $@. | SqlInjection.cs:18:21:18:29 | access to property Text : String | this TextBox text |
|
||||
| SqlInjection.cs:28:42:28:52 | access to local variable queryString | SqlInjection.cs:27:21:27:38 | call to method ReadLine : String | SqlInjection.cs:28:42:28:52 | access to local variable queryString | This query depends on $@. | SqlInjection.cs:27:21:27:38 | call to method ReadLine : String | this read from stdin |
|
||||
| SqlInjection.cs:29:50:29:52 | access to local variable cmd | SqlInjection.cs:27:21:27:38 | call to method ReadLine : String | SqlInjection.cs:29:50:29:52 | access to local variable cmd | This query depends on $@. | SqlInjection.cs:27:21:27:38 | call to method ReadLine : String | this read from stdin |
|
||||
edges
|
||||
| SqlInjection.cs:17:21:17:31 | access to local variable queryString : String | SqlInjection.cs:19:42:19:52 | access to local variable queryString | provenance | Sink:MaD:1 |
|
||||
| SqlInjection.cs:17:21:17:31 | access to local variable queryString : String | SqlInjection.cs:19:42:19:52 | access to local variable queryString : String | provenance | |
|
||||
| SqlInjection.cs:18:21:18:29 | access to property Text : String | SqlInjection.cs:17:21:17:31 | access to local variable queryString : String | provenance | |
|
||||
| SqlInjection.cs:19:21:19:23 | access to local variable cmd : SqlCommand | SqlInjection.cs:20:50:20:52 | access to local variable cmd | provenance | Sink:MaD:2 |
|
||||
| SqlInjection.cs:19:27:19:53 | object creation of type SqlCommand : SqlCommand | SqlInjection.cs:19:21:19:23 | access to local variable cmd : SqlCommand | provenance | |
|
||||
| SqlInjection.cs:19:42:19:52 | access to local variable queryString : String | SqlInjection.cs:19:27:19:53 | object creation of type SqlCommand : SqlCommand | provenance | MaD:4 |
|
||||
| SqlInjection.cs:26:21:26:31 | access to local variable queryString : String | SqlInjection.cs:28:42:28:52 | access to local variable queryString | provenance | Sink:MaD:1 |
|
||||
| SqlInjection.cs:26:21:26:31 | access to local variable queryString : String | SqlInjection.cs:28:42:28:52 | access to local variable queryString : String | provenance | |
|
||||
| SqlInjection.cs:27:21:27:38 | call to method ReadLine : String | SqlInjection.cs:26:21:26:31 | access to local variable queryString : String | provenance | Src:MaD:3 |
|
||||
| SqlInjection.cs:28:21:28:23 | access to local variable cmd : SqlCommand | SqlInjection.cs:29:50:29:52 | access to local variable cmd | provenance | Sink:MaD:2 |
|
||||
| SqlInjection.cs:28:27:28:53 | object creation of type SqlCommand : SqlCommand | SqlInjection.cs:28:21:28:23 | access to local variable cmd : SqlCommand | provenance | |
|
||||
| SqlInjection.cs:28:42:28:52 | access to local variable queryString : String | SqlInjection.cs:28:27:28:53 | object creation of type SqlCommand : SqlCommand | provenance | MaD:4 |
|
||||
models
|
||||
| 1 | Sink: Microsoft.Data.SqlClient; SqlCommand; false; SqlCommand; (System.String); ; Argument[0]; sql-injection; manual |
|
||||
| 2 | Sink: Microsoft.Data.SqlClient; SqlDataAdapter; false; SqlDataAdapter; (Microsoft.Data.SqlClient.SqlCommand); ; Argument[0]; sql-injection; manual |
|
||||
| 3 | Source: System; Console; false; ReadLine; ; ; ReturnValue; stdin; manual |
|
||||
| 4 | Summary: Microsoft.Data.SqlClient; SqlCommand; false; SqlCommand; (System.String); ; Argument[0]; Argument[this]; taint; manual |
|
||||
nodes
|
||||
| SqlInjection.cs:17:21:17:31 | access to local variable queryString : String | semmle.label | access to local variable queryString : String |
|
||||
| SqlInjection.cs:18:21:18:29 | access to property Text : String | semmle.label | access to property Text : String |
|
||||
| SqlInjection.cs:19:21:19:23 | access to local variable cmd : SqlCommand | semmle.label | access to local variable cmd : SqlCommand |
|
||||
| SqlInjection.cs:19:27:19:53 | object creation of type SqlCommand : SqlCommand | semmle.label | object creation of type SqlCommand : SqlCommand |
|
||||
| SqlInjection.cs:19:42:19:52 | access to local variable queryString | semmle.label | access to local variable queryString |
|
||||
| SqlInjection.cs:19:42:19:52 | access to local variable queryString : String | semmle.label | access to local variable queryString : String |
|
||||
| SqlInjection.cs:20:50:20:52 | access to local variable cmd | semmle.label | access to local variable cmd |
|
||||
| SqlInjection.cs:26:21:26:31 | access to local variable queryString : String | semmle.label | access to local variable queryString : String |
|
||||
| SqlInjection.cs:27:21:27:38 | call to method ReadLine : String | semmle.label | call to method ReadLine : String |
|
||||
| SqlInjection.cs:28:21:28:23 | access to local variable cmd : SqlCommand | semmle.label | access to local variable cmd : SqlCommand |
|
||||
| SqlInjection.cs:28:27:28:53 | object creation of type SqlCommand : SqlCommand | semmle.label | object creation of type SqlCommand : SqlCommand |
|
||||
| SqlInjection.cs:28:42:28:52 | access to local variable queryString | semmle.label | access to local variable queryString |
|
||||
| SqlInjection.cs:28:42:28:52 | access to local variable queryString : String | semmle.label | access to local variable queryString : String |
|
||||
| SqlInjection.cs:29:50:29:52 | access to local variable cmd | semmle.label | access to local variable cmd |
|
||||
subpaths
|
||||
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/threat-models
|
||||
extensible: threatModelConfiguration
|
||||
data:
|
||||
- ["local", true, 0]
|
||||
@@ -0,0 +1,4 @@
|
||||
query: Security Features/CWE-089/SqlInjection.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -0,0 +1,4 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/Microsoft.Data.SqlClient/6.0.2/Microsoft.Data.SqlClient.csproj
|
||||
semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Windows.cs
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj
|
||||
@@ -17,12 +17,12 @@ namespace Test
|
||||
{
|
||||
connection.Open();
|
||||
SqlCommand customerCommand = new SqlCommand("SELECT * FROM customers", connection);
|
||||
SqlDataReader customerReader = customerCommand.ExecuteReader();
|
||||
SqlDataReader customerReader = customerCommand.ExecuteReader(); // $ Source[cs/sql-injection]
|
||||
|
||||
while (customerReader.Read())
|
||||
{
|
||||
// BAD: Read from database, write it straight to another query
|
||||
SqlCommand secondCustomerCommand = new SqlCommand("SELECT * FROM customers WHERE customerName=" + customerReader.GetString(1), connection);
|
||||
SqlCommand secondCustomerCommand = new SqlCommand("SELECT * FROM customers WHERE customerName=" + customerReader.GetString(1), connection); // $ Alert[cs/sql-injection]
|
||||
}
|
||||
customerReader.Close();
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace Test
|
||||
|
||||
public void RunSQLFromFile()
|
||||
{
|
||||
using (FileStream fs = new FileStream("myfile.txt", FileMode.Open))
|
||||
using (FileStream fs = new FileStream("myfile.txt", FileMode.Open)) // $ Source[cs/sql-injection]
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(fs, Encoding.UTF8))
|
||||
{
|
||||
@@ -42,7 +42,7 @@ namespace Test
|
||||
continue;
|
||||
using (var connection = new SQLiteConnection(""))
|
||||
{
|
||||
var cmd = new SQLiteCommand(sql, connection);
|
||||
var cmd = new SQLiteCommand(sql, connection); // $ Alert[cs/sql-injection]
|
||||
cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ namespace Test
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ categoryTextBox.Text + "' ORDER BY PRICE";
|
||||
var adapter = new SqlDataAdapter(query1, connection);
|
||||
+ categoryTextBox.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
var adapter = new SqlDataAdapter(query1, connection); // $ Alert[cs/sql-injection]
|
||||
var result = new DataSet();
|
||||
adapter.Fill(result);
|
||||
}
|
||||
@@ -70,9 +70,9 @@ namespace Test
|
||||
{
|
||||
// BAD: Use EntityFramework direct Sql execution methods
|
||||
var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ categoryTextBox.Text + "' ORDER BY PRICE";
|
||||
context.Database.ExecuteSqlCommand(query1);
|
||||
context.Database.SqlQuery<string>(query1);
|
||||
+ categoryTextBox.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
context.Database.ExecuteSqlCommand(query1); // $ Alert[cs/sql-injection]
|
||||
context.Database.SqlQuery<string>(query1); // $ Alert[cs/sql-injection]
|
||||
// GOOD: Use EntityFramework direct Sql execution methods with parameter
|
||||
var query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY="
|
||||
+ "@p0 ORDER BY PRICE";
|
||||
@@ -84,8 +84,8 @@ namespace Test
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ box1.Text + "' ORDER BY PRICE";
|
||||
var adapter = new SqlDataAdapter(query1, connection);
|
||||
+ box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
var adapter = new SqlDataAdapter(query1, connection); // $ Alert[cs/sql-injection]
|
||||
var result = new DataSet();
|
||||
adapter.Fill(result);
|
||||
}
|
||||
@@ -94,9 +94,9 @@ namespace Test
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var queryString = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ box1.Text + "' ORDER BY PRICE";
|
||||
var cmd = new SqlCommand(queryString);
|
||||
var adapter = new SqlDataAdapter(cmd);
|
||||
+ box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
var cmd = new SqlCommand(queryString); // $ Alert[cs/sql-injection]
|
||||
var adapter = new SqlDataAdapter(cmd); // $ Alert[cs/sql-injection]
|
||||
var result = new DataSet();
|
||||
adapter.Fill(result);
|
||||
}
|
||||
@@ -105,9 +105,9 @@ namespace Test
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var queryString = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ Console.ReadLine()! + "' ORDER BY PRICE";
|
||||
var cmd = new SqlCommand(queryString);
|
||||
var adapter = new SqlDataAdapter(cmd);
|
||||
+ Console.ReadLine()! + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
var cmd = new SqlCommand(queryString); // $ Alert[cs/sql-injection]
|
||||
var adapter = new SqlDataAdapter(cmd); // $ Alert[cs/sql-injection]
|
||||
var result = new DataSet();
|
||||
adapter.Fill(result);
|
||||
}
|
||||
@@ -119,14 +119,14 @@ namespace Test
|
||||
public abstract class MyController : Controller
|
||||
{
|
||||
[HttpPost("{userId:string}")]
|
||||
public async Task<IActionResult> GetUserById([FromRoute] string userId, CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> GetUserById([FromRoute] string userId, CancellationToken cancellationToken) // $ Source[cs/sql-injection]
|
||||
{
|
||||
// This is a vulnerable method due to SQL injection
|
||||
string query = "SELECT * FROM Users WHERE UserId = '" + userId + "'";
|
||||
|
||||
using (SqlConnection connection = new SqlConnection("YourConnectionString"))
|
||||
{
|
||||
SqlCommand command = new SqlCommand(query, connection);
|
||||
SqlCommand command = new SqlCommand(query, connection); // $ Alert[cs/sql-injection]
|
||||
connection.Open();
|
||||
|
||||
SqlDataReader reader = command.ExecuteReader();
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
query: Security Features/CWE-089/SqlInjection.ql
|
||||
postprocess: utils/test/PrettyPrintModels.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace Test
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE";
|
||||
var result = connection.Query<object>(query);
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
var result = connection.Query<object>(query); // $ Alert[cs/sql-injection]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ namespace Test
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE";
|
||||
var result = await connection.QueryAsync<object>(query);
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
var result = await connection.QueryAsync<object>(query); // $ Alert[cs/sql-injection]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ namespace Test
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE";
|
||||
var result = await connection.QueryFirstAsync(query);
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
var result = await connection.QueryFirstAsync(query); // $ Alert[cs/sql-injection]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,9 +44,9 @@ namespace Test
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE";
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
|
||||
await connection.ExecuteAsync(query);
|
||||
await connection.ExecuteAsync(query); // $ Alert[cs/sql-injection]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ namespace Test
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE";
|
||||
connection.ExecuteScalar(query);
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
connection.ExecuteScalar(query); // $ Alert[cs/sql-injection]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ namespace Test
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE";
|
||||
connection.ExecuteReader(query);
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
connection.ExecuteReader(query); // $ Alert[cs/sql-injection]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +72,9 @@ namespace Test
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE";
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + box1.Text + "' ORDER BY PRICE"; // $ Source[cs/sql-injection]
|
||||
|
||||
var comDef = new CommandDefinition(query);
|
||||
var comDef = new CommandDefinition(query); // $ Alert[cs/sql-injection]
|
||||
var result = await connection.QueryFirstAsync(comDef);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ namespace TestSqlite
|
||||
public void InjectUntrustedData()
|
||||
{
|
||||
// BAD: untrusted data is not sanitized.
|
||||
SQLiteCommand cmd = new SQLiteCommand(untrustedData.Text);
|
||||
SQLiteCommand cmd = new SQLiteCommand(untrustedData.Text); // $ Alert[cs/sql-injection]
|
||||
|
||||
// BAD: untrusted data is not sanitized.
|
||||
using (var connection = new SQLiteConnection(connectionString))
|
||||
{
|
||||
cmd = new SQLiteCommand(untrustedData.Text, connection);
|
||||
cmd = new SQLiteCommand(untrustedData.Text, connection); // $ Source[cs/sql-injection] Alert[cs/sql-injection]
|
||||
}
|
||||
|
||||
SQLiteDataAdapter adapter;
|
||||
@@ -30,23 +30,23 @@ namespace TestSqlite
|
||||
// BAD: untrusted data is not sanitized.
|
||||
using (var connection = new SQLiteConnection(connectionString))
|
||||
{
|
||||
adapter = new SQLiteDataAdapter(untrustedData.Text, connection);
|
||||
adapter = new SQLiteDataAdapter(untrustedData.Text, connection); // $ Alert[cs/sql-injection]
|
||||
result = new DataSet();
|
||||
adapter.Fill(result);
|
||||
}
|
||||
|
||||
// BAD: untrusted data is not sanitized.
|
||||
adapter = new SQLiteDataAdapter(untrustedData.Text, connectionString);
|
||||
adapter = new SQLiteDataAdapter(untrustedData.Text, connectionString); // $ Alert[cs/sql-injection]
|
||||
result = new DataSet();
|
||||
adapter.Fill(result);
|
||||
|
||||
// BAD: untrusted data is not sanitized.
|
||||
adapter = new SQLiteDataAdapter(cmd);
|
||||
adapter = new SQLiteDataAdapter(cmd); // $ Alert[cs/sql-injection]
|
||||
result = new DataSet();
|
||||
adapter.Fill(result);
|
||||
|
||||
// BAD: untrusted data as filename is not sanitized.
|
||||
using (FileStream fs = new FileStream(untrustedData.Text, FileMode.Open))
|
||||
using (FileStream fs = new FileStream(untrustedData.Text, FileMode.Open)) // $ Source[cs/sql-injection]
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(fs, Encoding.UTF8))
|
||||
{
|
||||
@@ -58,7 +58,7 @@ namespace TestSqlite
|
||||
continue;
|
||||
using (var connection = new SQLiteConnection(""))
|
||||
{
|
||||
cmd = new SQLiteCommand(sql, connection);
|
||||
cmd = new SQLiteCommand(sql, connection); // $ Alert[cs/sql-injection]
|
||||
cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
@@ -66,4 +66,4 @@ namespace TestSqlite
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user