mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge branch 'main' into patch-7
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
description: Remove `ruby_element_reference_block` DB relation
|
||||
compatibility: backwards
|
||||
|
||||
ruby_element_reference_block.rel: delete
|
||||
BIN
ruby/extractor/Cargo.lock
generated
BIN
ruby/extractor/Cargo.lock
generated
Binary file not shown.
@@ -9,7 +9,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
tree-sitter = ">= 0.22.6"
|
||||
tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template.git", rev = "38d5004a797298dc42c85e7706c5ceac46a3f29f" }
|
||||
tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "dc2d7d6b50f9975bc3c35bbec0ba11b2617b736b" }
|
||||
tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "0ffe457fb6aabf064f173fd30ea356845cef2513" }
|
||||
clap = { version = "4.2", features = ["derive"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
|
||||
|
||||
@@ -1,7 +1,2 @@
|
||||
import os
|
||||
from create_database_utils import *
|
||||
from diagnostics_test_utils import *
|
||||
|
||||
run_codeql_database_create([], lang="ruby", runFunction = runSuccessfully, db = None)
|
||||
|
||||
check_diagnostics()
|
||||
def test(codeql, ruby):
|
||||
codeql.database.create()
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
"visibility": {
|
||||
"statusPage": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,2 @@
|
||||
import os
|
||||
from create_database_utils import *
|
||||
from diagnostics_test_utils import *
|
||||
|
||||
run_codeql_database_create([], lang="ruby", runFunction = runSuccessfully, db = None)
|
||||
|
||||
check_diagnostics()
|
||||
def test(codeql, ruby):
|
||||
codeql.database.create()
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
dependencies:
|
||||
codeql/ruby-all: '*'
|
||||
codeql/ruby-queries: '*'
|
||||
warnOnImplicitThis: true
|
||||
@@ -1 +0,0 @@
|
||||
These tests are still run with the legacy test runner
|
||||
@@ -1,3 +1,22 @@
|
||||
## 1.0.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Element references with blocks, such as `foo[:bar] { |x| puts x}`, are now parsed correctly.
|
||||
* The `CleartextSources.qll` library, used by `rb/clear-text-logging-sensitive-data` and `rb/clear-text-logging-sensitive-data`, has been updated to consider heuristics for additional categories of sensitive data.
|
||||
|
||||
## 1.0.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
ruby/ql/lib/change-notes/released/1.0.2.md
Normal file
3
ruby/ql/lib/change-notes/released/1.0.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.2
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,4 +1,6 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `CleartextSources.qll` library, used by `rb/clear-text-logging-sensitive-data` and `rb/clear-text-logging-sensitive-data`, has been updated to consider heuristics for additional categories of sensitive data.
|
||||
## 1.0.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Element references with blocks, such as `foo[:bar] { |x| puts x}`, are now parsed correctly.
|
||||
* The `CleartextSources.qll` library, used by `rb/clear-text-logging-sensitive-data` and `rb/clear-text-logging-sensitive-data`, has been updated to consider heuristics for additional categories of sensitive data.
|
||||
3
ruby/ql/lib/change-notes/released/1.0.4.md
Normal file
3
ruby/ql/lib/change-notes/released/1.0.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.4
|
||||
|
||||
No user-facing changes.
|
||||
3
ruby/ql/lib/change-notes/released/1.0.5.md
Normal file
3
ruby/ql/lib/change-notes/released/1.0.5.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.5
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.1
|
||||
lastReleaseVersion: 1.0.5
|
||||
|
||||
@@ -112,7 +112,7 @@ class ElementReferenceImpl extends MethodCallImpl, TElementReference {
|
||||
|
||||
final override string getMethodNameImpl() { result = "[]" }
|
||||
|
||||
final override Block getBlockImpl() { none() }
|
||||
final override Block getBlockImpl() { toGenerated(result) = g.getBlock() }
|
||||
}
|
||||
|
||||
abstract class SuperCallImpl extends MethodCallImpl, TSuperCall { }
|
||||
|
||||
@@ -633,6 +633,9 @@ module Ruby {
|
||||
/** Gets the name of the primary QL class for this element. */
|
||||
final override string getAPrimaryQlClass() { result = "ElementReference" }
|
||||
|
||||
/** Gets the node corresponding to the field `block`. */
|
||||
final AstNode getBlock() { ruby_element_reference_block(this, result) }
|
||||
|
||||
/** Gets the node corresponding to the field `object`. */
|
||||
final UnderscorePrimary getObject() { ruby_element_reference_def(this, result) }
|
||||
|
||||
@@ -641,7 +644,9 @@ module Ruby {
|
||||
|
||||
/** Gets a field or child node of this node. */
|
||||
final override AstNode getAFieldOrChild() {
|
||||
ruby_element_reference_def(this, result) or ruby_element_reference_child(this, _, result)
|
||||
ruby_element_reference_block(this, result) or
|
||||
ruby_element_reference_def(this, result) or
|
||||
ruby_element_reference_child(this, _, result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
11
ruby/ql/lib/codeql/ruby/controlflow/internal/Guards.qll
Normal file
11
ruby/ql/lib/codeql/ruby/controlflow/internal/Guards.qll
Normal file
@@ -0,0 +1,11 @@
|
||||
private import codeql.ruby.CFG
|
||||
|
||||
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
|
||||
pragma[nomagic]
|
||||
predicate guardControlsBlock(CfgNodes::AstCfgNode guard, BasicBlock bb, boolean branch) {
|
||||
exists(ConditionBlock conditionBlock, SuccessorTypes::ConditionalSuccessor s |
|
||||
guard = conditionBlock.getLastNode() and
|
||||
s.getValue() = branch and
|
||||
conditionBlock.controls(bb, s)
|
||||
)
|
||||
}
|
||||
@@ -176,9 +176,6 @@ module Ssa {
|
||||
|
||||
override string toString() { result = this.getControlFlowNode().toString() }
|
||||
|
||||
/** Gets the location of this SSA definition. */
|
||||
Location getLocation() { result = this.getControlFlowNode().getLocation() }
|
||||
|
||||
/** Gets the scope of this SSA definition. */
|
||||
CfgScope getScope() { result = this.getBasicBlock().getScope() }
|
||||
}
|
||||
@@ -205,8 +202,17 @@ module Ssa {
|
||||
final VariableWriteAccessCfgNode getWriteAccess() { result = write }
|
||||
|
||||
/**
|
||||
* Holds if this SSA definition represents a direct assignment of `value`
|
||||
* to the underlying variable.
|
||||
* Holds if this SSA definition assigns `value` to the underlying variable.
|
||||
*
|
||||
* This is either a direct assignment, `x = value`, or an assignment via
|
||||
* simple pattern matching
|
||||
*
|
||||
* ```rb
|
||||
* case value
|
||||
* in Foo => x then ...
|
||||
* in y => then ...
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
predicate assigns(CfgNodes::ExprCfgNode value) {
|
||||
exists(CfgNodes::ExprNodes::AssignExprCfgNode a, BasicBlock bb, int i |
|
||||
@@ -214,6 +220,14 @@ module Ssa {
|
||||
a = bb.getNode(i) and
|
||||
value = a.getRhs()
|
||||
)
|
||||
or
|
||||
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::AstCfgNode pattern |
|
||||
case.getValue() = value and
|
||||
pattern = case.getBranch(_).(CfgNodes::ExprNodes::InClauseCfgNode).getPattern()
|
||||
|
|
||||
this.getWriteAccess() =
|
||||
[pattern, pattern.(CfgNodes::ExprNodes::AsPatternCfgNode).getVariableAccess()]
|
||||
)
|
||||
}
|
||||
|
||||
final override string toString() { result = write.toString() }
|
||||
|
||||
@@ -113,16 +113,6 @@ class DataFlowCallable extends TDataFlowCallable {
|
||||
this instanceof TLibraryCallable and
|
||||
result instanceof EmptyLocation
|
||||
}
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
|
||||
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by file, startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,16 +144,6 @@ abstract class DataFlowCall extends TDataFlowCall {
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCall c, int startline, int startcolumn |
|
||||
c.hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1093,8 +1073,7 @@ private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruct
|
||||
singletonMethodOnInstance(_, _, nodeFromPreExpr.getExpr())
|
||||
)
|
||||
|
|
||||
nodeFromPreExpr =
|
||||
LocalFlow::getParameterDefNode(p.getParameter()).getDefinitionExt().getARead()
|
||||
nodeFromPreExpr = getParameterDef(p.getParameter()).getARead()
|
||||
or
|
||||
nodeFromPreExpr = p.(SelfParameterNodeImpl).getSelfDefinition().getARead()
|
||||
)
|
||||
|
||||
@@ -72,134 +72,48 @@ CfgNodes::ExprCfgNode getAPostUpdateNodeForArg(Argument arg) {
|
||||
not exists(getALastEvalNode(result))
|
||||
}
|
||||
|
||||
/** An SSA definition into which another SSA definition may flow. */
|
||||
class SsaInputDefinitionExt extends SsaImpl::DefinitionExt {
|
||||
SsaInputDefinitionExt() {
|
||||
this instanceof Ssa::PhiNode
|
||||
/** Gets the SSA definition node corresponding to parameter `p`. */
|
||||
pragma[nomagic]
|
||||
SsaImpl::DefinitionExt getParameterDef(NamedParameter p) {
|
||||
exists(BasicBlock bb, int i |
|
||||
bb.getNode(i).getAstNode() = p.getDefiningAccess() and
|
||||
result.definesAt(_, bb, i, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Provides logic related to SSA. */
|
||||
module SsaFlow {
|
||||
private module Impl = SsaImpl::DataFlowIntegration;
|
||||
|
||||
private ParameterNodeImpl toParameterNode(SsaImpl::ParameterExt p) {
|
||||
result = TNormalParameterNode(p.asParameter())
|
||||
or
|
||||
this instanceof SsaImpl::PhiReadNode
|
||||
result = TSelfMethodParameterNode(p.asMethodSelf())
|
||||
or
|
||||
result = TSelfToplevelParameterNode(p.asToplevelSelf())
|
||||
}
|
||||
|
||||
predicate hasInputFromBlock(SsaImpl::DefinitionExt def, BasicBlock bb, int i, BasicBlock input) {
|
||||
SsaImpl::lastRefBeforeRedefExt(def, bb, i, input, this)
|
||||
Impl::Node asNode(Node n) {
|
||||
n = TSsaNode(result)
|
||||
or
|
||||
result.(Impl::ExprNode).getExpr() = n.asExpr()
|
||||
or
|
||||
result.(Impl::ExprPostUpdateNode).getExpr() = n.(PostUpdateNode).getPreUpdateNode().asExpr()
|
||||
or
|
||||
n = toParameterNode(result.(Impl::ParameterNode).getParameter())
|
||||
}
|
||||
|
||||
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
}
|
||||
|
||||
predicate localMustFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
Impl::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides predicates related to local data flow. */
|
||||
module LocalFlow {
|
||||
/**
|
||||
* Holds if `nodeFrom` is a node for SSA definition `def`, which can reach `next`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowSsaInputFromDef(
|
||||
SsaDefinitionExtNode nodeFrom, SsaImpl::DefinitionExt def, SsaInputNode nodeTo
|
||||
) {
|
||||
exists(BasicBlock bb, int i, BasicBlock input, SsaInputDefinitionExt next |
|
||||
next.hasInputFromBlock(def, bb, i, input) and
|
||||
def = nodeFrom.getDefinitionExt() and
|
||||
def.definesAt(_, bb, i, _) and
|
||||
nodeTo = TSsaInputNode(next, input)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` is a last read of SSA definition `def`, which
|
||||
* can reach `nodeTo`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate localFlowSsaInputFromRead(SsaImpl::DefinitionExt def, Node nodeFrom, SsaInputNode nodeTo) {
|
||||
exists(
|
||||
BasicBlock bb, int i, CfgNodes::ExprCfgNode exprFrom, BasicBlock input,
|
||||
SsaInputDefinitionExt next
|
||||
|
|
||||
next.hasInputFromBlock(def, bb, i, input) and
|
||||
exprFrom = bb.getNode(i) and
|
||||
exprFrom.getExpr() instanceof VariableReadAccess and
|
||||
exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode().asExpr()] and
|
||||
nodeTo = TSsaInputNode(next, input)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the SSA definition node corresponding to parameter `p`. */
|
||||
pragma[nomagic]
|
||||
SsaDefinitionExtNode getParameterDefNode(NamedParameter p) {
|
||||
exists(BasicBlock bb, int i |
|
||||
bb.getNode(i).getAstNode() = p.getDefiningAccess() and
|
||||
result.getDefinitionExt().definesAt(_, bb, i, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` is a parameter node, and `nodeTo` is a corresponding SSA node.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate localFlowSsaParamInput(ParameterNodeImpl nodeFrom, SsaDefinitionExtNode nodeTo) {
|
||||
nodeTo = getParameterDefNode(nodeFrom.getParameter())
|
||||
or
|
||||
nodeTo.getDefinitionExt() = nodeFrom.(SelfParameterNodeImpl).getSelfDefinition()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
|
||||
* involving SSA definition `def`.
|
||||
*/
|
||||
predicate localSsaFlowStepUseUse(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
SsaImpl::adjacentReadPairExt(def, nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if SSA definition `def` assigns `value` to the underlying variable.
|
||||
*
|
||||
* This is either a direct assignment, `x = value`, or an assignment via
|
||||
* simple pattern matching
|
||||
*
|
||||
* ```rb
|
||||
* case value
|
||||
* in Foo => x then ...
|
||||
* in y => then ...
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
predicate ssaDefAssigns(Ssa::WriteDefinition def, CfgNodes::ExprCfgNode value) {
|
||||
def.assigns(value)
|
||||
or
|
||||
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::AstCfgNode pattern |
|
||||
case.getValue() = value and
|
||||
pattern = case.getBranch(_).(CfgNodes::ExprNodes::InClauseCfgNode).getPattern()
|
||||
|
|
||||
def.getWriteAccess() = pattern
|
||||
or
|
||||
def.getWriteAccess() = pattern.(CfgNodes::ExprNodes::AsPatternCfgNode).getVariableAccess()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
|
||||
* SSA definition `def`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate localSsaFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
// Flow from assignment into SSA definition
|
||||
ssaDefAssigns(def, nodeFrom.asExpr()) and
|
||||
nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def
|
||||
or
|
||||
// Flow from SSA definition to first read
|
||||
def = nodeFrom.(SsaDefinitionExtNode).getDefinitionExt() and
|
||||
SsaImpl::firstReadExt(def, nodeTo.asExpr())
|
||||
or
|
||||
// Flow from post-update read to next read
|
||||
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode(), nodeTo)
|
||||
or
|
||||
// Flow into phi (read) SSA definition node from def
|
||||
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
|
||||
or
|
||||
nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def and
|
||||
def = nodeFrom.(SsaInputNode).getDefinitionExt()
|
||||
or
|
||||
localFlowSsaParamInput(nodeFrom, nodeTo) and
|
||||
def = nodeTo.(SsaDefinitionExtNode).getDefinitionExt()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
|
||||
@@ -240,7 +154,7 @@ module LocalFlow {
|
||||
p.(KeywordParameter).getDefaultValue() = nodeFrom.asExpr().getExpr()
|
||||
)
|
||||
or
|
||||
nodeTo.(BlockArgumentNode).getParameterNode(true) = nodeFrom
|
||||
nodeTo.(ImplicitBlockArgumentNode).getParameterNode(true) = nodeFrom
|
||||
}
|
||||
|
||||
predicate flowSummaryLocalStep(
|
||||
@@ -253,21 +167,13 @@ module LocalFlow {
|
||||
}
|
||||
|
||||
predicate localMustFlowStep(Node node1, Node node2) {
|
||||
LocalFlow::localFlowSsaParamInput(node1, node2)
|
||||
or
|
||||
exists(SsaImpl::Definition def |
|
||||
def.(Ssa::WriteDefinition).assigns(node1.asExpr()) and
|
||||
node2.(SsaDefinitionExtNode).getDefinitionExt() = def
|
||||
or
|
||||
def = node1.(SsaDefinitionExtNode).getDefinitionExt() and
|
||||
node2.asExpr() = SsaImpl::getARead(def)
|
||||
)
|
||||
SsaFlow::localMustFlowStep(_, node1, node2)
|
||||
or
|
||||
node1.asExpr() = node2.asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
|
||||
or
|
||||
node1.asExpr() = node2.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
|
||||
or
|
||||
node1 = node2.(BlockArgumentNode).getParameterNode(true)
|
||||
node1 = node2.(ImplicitBlockArgumentNode).getParameterNode(true)
|
||||
or
|
||||
node1 =
|
||||
unique(FlowSummaryNode n1 |
|
||||
@@ -347,13 +253,12 @@ module VariableCapture {
|
||||
or
|
||||
exists(Ssa::Definition def |
|
||||
def.getARead() = e2 and
|
||||
LocalFlow::ssaDefAssigns(def.getAnUltimateDefinition(), e1)
|
||||
def.getAnUltimateDefinition().(Ssa::WriteDefinition).assigns(e1)
|
||||
)
|
||||
}
|
||||
|
||||
private module CaptureInput implements Shared::InputSig<Location> {
|
||||
private import ruby as R
|
||||
private import codeql.ruby.controlflow.ControlFlowGraph
|
||||
private import codeql.ruby.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.ruby.controlflow.BasicBlocks as BasicBlocks
|
||||
private import TaintTrackingPrivate as TaintTrackingPrivate
|
||||
|
||||
@@ -361,6 +266,8 @@ module VariableCapture {
|
||||
Callable getEnclosingCallable() { result = this.getScope() }
|
||||
}
|
||||
|
||||
class ControlFlowNode = Cfg::CfgNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = bb.getImmediateDominator()
|
||||
}
|
||||
@@ -537,23 +444,14 @@ private module Cached {
|
||||
newtype TNode =
|
||||
TExprNode(CfgNodes::ExprCfgNode n) or
|
||||
TReturningNode(CfgNodes::ReturningCfgNode n) { exists(n.getReturnedValueNode()) } or
|
||||
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) or
|
||||
TSsaInputNode(SsaInputDefinitionExt def, BasicBlock input) {
|
||||
def.hasInputFromBlock(_, _, _, input)
|
||||
} or
|
||||
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or
|
||||
TCapturedVariableNode(VariableCapture::CapturedVariable v) or
|
||||
TNormalParameterNode(Parameter p) {
|
||||
p instanceof SimpleParameter or
|
||||
p instanceof OptionalParameter or
|
||||
p instanceof KeywordParameter or
|
||||
p instanceof HashSplatParameter or
|
||||
p instanceof SplatParameter
|
||||
} or
|
||||
TNormalParameterNode(SsaImpl::NormalParameter p) or
|
||||
TSelfMethodParameterNode(MethodBase m) or
|
||||
TSelfToplevelParameterNode(Toplevel t) or
|
||||
TLambdaSelfReferenceNode(Callable c) { lambdaCreationExpr(_, _, c) } or
|
||||
TBlockParameterNode(MethodBase m) or
|
||||
TBlockArgumentNode(CfgNodes::ExprNodes::CallCfgNode yield) {
|
||||
TImplicitBlockParameterNode(MethodBase m) { not m.getAParameter() instanceof BlockParameter } or
|
||||
TImplicitBlockArgumentNode(CfgNodes::ExprNodes::CallCfgNode yield) {
|
||||
yield = any(BlockParameterNode b).getAYieldCall()
|
||||
} or
|
||||
TSynthHashSplatParameterNode(DataFlowCallable c) {
|
||||
@@ -599,7 +497,7 @@ private module Cached {
|
||||
class TSelfParameterNode = TSelfMethodParameterNode or TSelfToplevelParameterNode;
|
||||
|
||||
class TSourceParameterNode =
|
||||
TNormalParameterNode or TBlockParameterNode or TSelfParameterNode or
|
||||
TNormalParameterNode or TImplicitBlockParameterNode or TSelfParameterNode or
|
||||
TSynthHashSplatParameterNode or TSynthSplatParameterNode;
|
||||
|
||||
cached
|
||||
@@ -617,16 +515,13 @@ private module Cached {
|
||||
(
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
exists(SsaImpl::DefinitionExt def |
|
||||
exists(SsaImpl::DefinitionExt def, boolean isUseStep |
|
||||
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep) and
|
||||
// captured variables are handled by the shared `VariableCapture` library
|
||||
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
||||
|
|
||||
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo)
|
||||
isUseStep = false
|
||||
or
|
||||
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
|
||||
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
|
||||
or
|
||||
LocalFlow::localFlowSsaInputFromRead(def, nodeFrom, nodeTo) and
|
||||
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
|
||||
)
|
||||
or
|
||||
@@ -642,9 +537,7 @@ private module Cached {
|
||||
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
|
||||
or
|
||||
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
|
||||
SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _)
|
||||
or
|
||||
// Simple flow through library code is included in the exposed local
|
||||
// step relation, even though flow is technically inter-procedural
|
||||
@@ -658,11 +551,7 @@ private module Cached {
|
||||
predicate localFlowStepTypeTracker(Node nodeFrom, Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
|
||||
or
|
||||
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
|
||||
or
|
||||
LocalFlow::localFlowSsaInputFromRead(_, nodeFrom, nodeTo)
|
||||
SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _)
|
||||
or
|
||||
VariableCapture::flowInsensitiveStep(nodeFrom, nodeTo)
|
||||
or
|
||||
@@ -672,7 +561,8 @@ private module Cached {
|
||||
|
||||
/** Holds if `n` wraps an SSA definition without ingoing flow. */
|
||||
private predicate entrySsaDefinition(SsaDefinitionExtNode n) {
|
||||
n.getDefinitionExt() = any(SsaImpl::WriteDefinition def | not LocalFlow::ssaDefAssigns(def, _))
|
||||
n.getDefinitionExt() =
|
||||
any(SsaImpl::WriteDefinition def | not def.(Ssa::WriteDefinition).assigns(_))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -712,13 +602,15 @@ private module Cached {
|
||||
// Ensure all entry SSA definitions are local sources, except those that correspond
|
||||
// to parameters (which are themselves local sources)
|
||||
entrySsaDefinition(n) and
|
||||
not LocalFlow::localFlowSsaParamInput(_, n)
|
||||
not exists(SsaImpl::ParameterExt p |
|
||||
p.isInitializedBy(n.(SsaDefinitionExtNode).getDefinitionExt())
|
||||
)
|
||||
or
|
||||
isStoreTargetNode(n)
|
||||
or
|
||||
TypeTrackingInput::loadStep(_, n, _)
|
||||
or
|
||||
n instanceof BlockArgumentNode
|
||||
n instanceof ImplicitBlockArgumentNode
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -822,11 +714,7 @@ import Cached
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) {
|
||||
n.(SsaDefinitionExtNode).isHidden()
|
||||
or
|
||||
n instanceof SsaInputNode
|
||||
or
|
||||
n = LocalFlow::getParameterDefNode(_)
|
||||
n.(SsaNode).isHidden()
|
||||
or
|
||||
exists(AstNode desug |
|
||||
isDesugarNode(desug) and
|
||||
@@ -858,33 +746,55 @@ predicate nodeIsHidden(Node n) {
|
||||
or
|
||||
n instanceof CaptureNode
|
||||
or
|
||||
n instanceof BlockArgumentNode
|
||||
n instanceof ImplicitBlockArgumentNode
|
||||
}
|
||||
|
||||
/** An SSA definition, viewed as a node in a data flow graph. */
|
||||
class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
|
||||
/** An SSA node. */
|
||||
abstract class SsaNode extends NodeImpl, TSsaNode {
|
||||
SsaImpl::DataFlowIntegration::SsaNode node;
|
||||
SsaImpl::DefinitionExt def;
|
||||
|
||||
SsaDefinitionExtNode() { this = TSsaDefinitionExtNode(def) }
|
||||
SsaNode() {
|
||||
this = TSsaNode(node) and
|
||||
def = node.getDefinitionExt()
|
||||
}
|
||||
|
||||
/** Gets the underlying SSA definition. */
|
||||
SsaImpl::DefinitionExt getDefinitionExt() { result = def }
|
||||
|
||||
/** Holds if this node should be hidden from path explanations. */
|
||||
abstract predicate isHidden();
|
||||
|
||||
override Location getLocationImpl() { result = node.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = node.toString() }
|
||||
}
|
||||
|
||||
/** An (extended) SSA definition, viewed as a node in a data flow graph. */
|
||||
class SsaDefinitionExtNode extends SsaNode {
|
||||
override SsaImpl::DataFlowIntegration::SsaDefinitionExtNode node;
|
||||
|
||||
/** Gets the underlying variable. */
|
||||
Variable getVariable() { result = def.getSourceVariable() }
|
||||
|
||||
/** Holds if this node should be hidden from path explanations. */
|
||||
predicate isHidden() {
|
||||
override predicate isHidden() {
|
||||
not def instanceof Ssa::WriteDefinition
|
||||
or
|
||||
isDesugarNode(def.(Ssa::WriteDefinition).getWriteAccess().getExpr())
|
||||
or
|
||||
def = getParameterDef(_)
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = def.getBasicBlock().getScope() }
|
||||
}
|
||||
|
||||
override Location getLocationImpl() { result = def.getLocation() }
|
||||
class SsaDefinitionNodeImpl extends SsaDefinitionExtNode {
|
||||
Ssa::Definition ssaDef;
|
||||
|
||||
override string toStringImpl() { result = def.toString() }
|
||||
SsaDefinitionNodeImpl() { ssaDef = def }
|
||||
|
||||
override Location getLocationImpl() { result = ssaDef.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = ssaDef.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -922,20 +832,12 @@ class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
|
||||
*
|
||||
* both inputs into the phi read node after the outer condition are guarded.
|
||||
*/
|
||||
class SsaInputNode extends NodeImpl, TSsaInputNode {
|
||||
SsaImpl::DefinitionExt def;
|
||||
BasicBlock input;
|
||||
class SsaInputNode extends SsaNode {
|
||||
override SsaImpl::DataFlowIntegration::SsaInputNode node;
|
||||
|
||||
SsaInputNode() { this = TSsaInputNode(def, input) }
|
||||
override predicate isHidden() { any() }
|
||||
|
||||
/** Gets the underlying SSA definition. */
|
||||
SsaImpl::DefinitionExt getDefinitionExt() { result = def }
|
||||
|
||||
override CfgScope getCfgScope() { result = input.getScope() }
|
||||
|
||||
override Location getLocationImpl() { result = input.getLastNode().getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "[input] " + def }
|
||||
override CfgScope getCfgScope() { result = node.getDefinitionExt().getBasicBlock().getScope() }
|
||||
}
|
||||
|
||||
/** An SSA definition for a `self` variable. */
|
||||
@@ -1023,7 +925,7 @@ private module ParameterNodes {
|
||||
* flow graph.
|
||||
*/
|
||||
class NormalParameterNode extends ParameterNodeImpl, TNormalParameterNode {
|
||||
private Parameter parameter;
|
||||
Parameter parameter;
|
||||
|
||||
NormalParameterNode() { this = TNormalParameterNode(parameter) }
|
||||
|
||||
@@ -1052,6 +954,9 @@ private module ParameterNodes {
|
||||
// There are no positional parameters after the splat
|
||||
not exists(SimpleParameter p, int m | m > n | p = callable.getParameter(m))
|
||||
)
|
||||
or
|
||||
parameter = callable.getAParameter().(BlockParameter) and
|
||||
pos.isBlock()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1159,24 +1064,32 @@ private module ParameterNodes {
|
||||
* The value of a block parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class BlockParameterNode extends ParameterNodeImpl, TBlockParameterNode {
|
||||
private MethodBase method;
|
||||
|
||||
BlockParameterNode() { this = TBlockParameterNode(method) }
|
||||
|
||||
final MethodBase getMethod() { result = method }
|
||||
|
||||
override Parameter getParameter() {
|
||||
result = method.getAParameter() and result instanceof BlockParameter
|
||||
}
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
c.asCfgScope() = method and pos.isBlock()
|
||||
}
|
||||
abstract class BlockParameterNode extends ParameterNodeImpl {
|
||||
abstract MethodBase getMethod();
|
||||
|
||||
CfgNodes::ExprNodes::CallCfgNode getAYieldCall() {
|
||||
this.getMethod() = result.getExpr().(YieldCall).getEnclosingMethod()
|
||||
}
|
||||
}
|
||||
|
||||
private class ExplicitBlockParameterNode extends BlockParameterNode, NormalParameterNode {
|
||||
override BlockParameter parameter;
|
||||
|
||||
final override MethodBase getMethod() { result.getAParameter() = parameter }
|
||||
}
|
||||
|
||||
private class ImplicitBlockParameterNode extends BlockParameterNode, TImplicitBlockParameterNode {
|
||||
private MethodBase method;
|
||||
|
||||
ImplicitBlockParameterNode() { this = TImplicitBlockParameterNode(method) }
|
||||
|
||||
final override MethodBase getMethod() { result = method }
|
||||
|
||||
override Parameter getParameter() { none() }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
c.asCfgScope() = method and pos.isBlock()
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = method }
|
||||
|
||||
@@ -1449,10 +1362,10 @@ module ArgumentNodes {
|
||||
}
|
||||
}
|
||||
|
||||
class BlockArgumentNode extends NodeImpl, ArgumentNode, TBlockArgumentNode {
|
||||
class ImplicitBlockArgumentNode extends NodeImpl, ArgumentNode, TImplicitBlockArgumentNode {
|
||||
CfgNodes::ExprNodes::CallCfgNode yield;
|
||||
|
||||
BlockArgumentNode() { this = TBlockArgumentNode(yield) }
|
||||
ImplicitBlockArgumentNode() { this = TImplicitBlockArgumentNode(yield) }
|
||||
|
||||
CfgNodes::ExprNodes::CallCfgNode getYieldCall() { result = yield }
|
||||
|
||||
@@ -1890,7 +1803,7 @@ predicate jumpStep(Node pred, Node succ) {
|
||||
or
|
||||
any(AdditionalJumpStep s).step(pred, succ)
|
||||
or
|
||||
succ.(BlockArgumentNode).getParameterNode(false) = pred
|
||||
succ.(ImplicitBlockArgumentNode).getParameterNode(false) = pred
|
||||
}
|
||||
|
||||
private ContentSet getArrayContent(int n) {
|
||||
@@ -2074,9 +1987,6 @@ DataFlowType getNodeType(Node n) {
|
||||
result = TUnknownDataFlowType()
|
||||
}
|
||||
|
||||
/** Gets a string representation of a `DataFlowType`. */
|
||||
string ppReprType(DataFlowType t) { none() }
|
||||
|
||||
pragma[inline]
|
||||
private predicate compatibleTypesNonSymRefl(DataFlowType t1, DataFlowType t2) {
|
||||
t1 != TUnknownDataFlowType() and
|
||||
@@ -2087,7 +1997,6 @@ private predicate compatibleTypesNonSymRefl(DataFlowType t1, DataFlowType t2) {
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
t1 = t2
|
||||
or
|
||||
@@ -2181,8 +2090,6 @@ class NodeRegion instanceof Unit {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { none() }
|
||||
|
||||
int totalOrder() { result = 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2239,7 +2146,7 @@ private predicate lambdaCallExpr(
|
||||
*/
|
||||
predicate lambdaSourceCall(CfgNodes::ExprNodes::CallCfgNode call, LambdaCallKind kind, Node receiver) {
|
||||
kind = TYieldCallKind() and
|
||||
call = receiver.(BlockArgumentNode).getYieldCall()
|
||||
call = receiver.(ImplicitBlockArgumentNode).getYieldCall()
|
||||
or
|
||||
kind = TLambdaCallKind() and
|
||||
lambdaCallExpr(call, receiver.asExpr())
|
||||
|
||||
@@ -6,6 +6,7 @@ private import codeql.ruby.typetracking.internal.TypeTrackingImpl
|
||||
private import codeql.ruby.dataflow.SSA
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import SsaImpl as SsaImpl
|
||||
|
||||
/**
|
||||
* An element, viewed as a node in a data flow graph. Either an expression
|
||||
@@ -360,16 +361,12 @@ class PostUpdateNode extends Node {
|
||||
}
|
||||
|
||||
/** An SSA definition, viewed as a node in a data flow graph. */
|
||||
class SsaDefinitionNode extends Node instanceof SsaDefinitionExtNode {
|
||||
Ssa::Definition def;
|
||||
|
||||
SsaDefinitionNode() { this = TSsaDefinitionExtNode(def) }
|
||||
|
||||
class SsaDefinitionNode extends Node instanceof SsaDefinitionNodeImpl {
|
||||
/** Gets the underlying SSA definition. */
|
||||
Ssa::Definition getDefinition() { result = def }
|
||||
Ssa::Definition getDefinition() { result = super.getDefinitionExt() }
|
||||
|
||||
/** Gets the underlying variable. */
|
||||
Variable getVariable() { result = def.getSourceVariable() }
|
||||
Variable getVariable() { result = this.getDefinition().getSourceVariable() }
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -870,56 +867,7 @@ private predicate sameSourceVariable(Ssa::Definition def1, Ssa::Definition def2)
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
private import SsaImpl as SsaImpl
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate guardChecksSsaDef(CfgNodes::AstCfgNode g, boolean branch, Ssa::Definition def) {
|
||||
guardChecks(g, def.getARead(), branch)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate guardControlsSsaRead(
|
||||
CfgNodes::AstCfgNode g, boolean branch, Ssa::Definition def, Node n
|
||||
) {
|
||||
def.getARead() = n.asExpr() and
|
||||
guardControlsBlock(g, n.asExpr().getBasicBlock(), branch)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate guardControlsPhiInput(
|
||||
CfgNodes::AstCfgNode g, boolean branch, Ssa::Definition def, BasicBlock input,
|
||||
SsaInputDefinitionExt phi
|
||||
) {
|
||||
phi.hasInputFromBlock(def, _, _, input) and
|
||||
(
|
||||
guardControlsBlock(g, input, branch)
|
||||
or
|
||||
exists(SuccessorTypes::ConditionalSuccessor s |
|
||||
g = input.getLastNode() and
|
||||
s.getValue() = branch and
|
||||
input.getASuccessor(s) = phi.getBasicBlock()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
Node getABarrierNode() {
|
||||
exists(CfgNodes::AstCfgNode g, boolean branch, Ssa::Definition def |
|
||||
guardChecksSsaDef(g, branch, def) and
|
||||
guardControlsSsaRead(g, branch, def, result)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
CfgNodes::AstCfgNode g, boolean branch, Ssa::Definition def, BasicBlock input,
|
||||
SsaInputDefinitionExt phi
|
||||
|
|
||||
guardChecksSsaDef(g, branch, def) and
|
||||
guardControlsPhiInput(g, branch, def, input, phi) and
|
||||
result = TSsaInputNode(phi, input)
|
||||
)
|
||||
or
|
||||
result.asExpr() = getAMaybeGuardedCapturedDef().getARead()
|
||||
}
|
||||
private import codeql.ruby.controlflow.internal.Guards
|
||||
|
||||
/**
|
||||
* Gets an implicit entry definition for a captured variable that
|
||||
@@ -928,6 +876,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
* This is restricted to calls where the variable is captured inside a
|
||||
* block.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Ssa::CapturedEntryDefinition getAMaybeGuardedCapturedDef() {
|
||||
exists(
|
||||
CfgNodes::ExprCfgNode g, boolean branch, CfgNodes::ExprCfgNode testedNode,
|
||||
@@ -940,15 +889,14 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
sameSourceVariable(def, result)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
|
||||
private predicate guardControlsBlock(CfgNodes::AstCfgNode guard, BasicBlock bb, boolean branch) {
|
||||
exists(ConditionBlock conditionBlock, SuccessorTypes::ConditionalSuccessor s |
|
||||
guard = conditionBlock.getLastNode() and
|
||||
s.getValue() = branch and
|
||||
conditionBlock.controls(bb, s)
|
||||
)
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
Node getABarrierNode() {
|
||||
SsaFlow::asNode(result) =
|
||||
SsaImpl::DataFlowIntegration::BarrierGuard<guardChecks/3>::getABarrierNode()
|
||||
or
|
||||
result.asExpr() = getAMaybeGuardedCapturedDef().getARead()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,16 +6,19 @@ private import codeql.ruby.dataflow.SSA
|
||||
private import codeql.ruby.ast.Variable
|
||||
private import Cfg::CfgNodes::ExprNodes
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
private import codeql.ruby.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.ruby.controlflow.BasicBlocks as BasicBlocks
|
||||
|
||||
class BasicBlock = BasicBlocks::BasicBlock;
|
||||
|
||||
class ControlFlowNode = Cfg::CfgNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock = BasicBlocks::ExitBasicBlock;
|
||||
class ExitBasicBlock extends BasicBlock, BasicBlocks::ExitBasicBlock { }
|
||||
|
||||
class SourceVariable = LocalVariable;
|
||||
|
||||
@@ -62,7 +65,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
private import SsaImplCommon::Make<Location, SsaInput> as Impl
|
||||
import SsaImplCommon::Make<Location, SsaInput> as Impl
|
||||
|
||||
class Definition = Impl::Definition;
|
||||
|
||||
@@ -280,15 +283,6 @@ private predicate adjacentDefSkipUncertainReads(
|
||||
SsaInput::variableRead(bb2, i2, _, true)
|
||||
}
|
||||
|
||||
/** Same as `adjacentDefReadExt`, but skips uncertain reads. */
|
||||
pragma[nomagic]
|
||||
private predicate adjacentDefSkipUncertainReadsExt(
|
||||
DefinitionExt def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
|
||||
) {
|
||||
adjacentDefReachesReadExt(def, bb1, i1, bb2, i2) and
|
||||
SsaInput::variableRead(bb2, i2, _, true)
|
||||
}
|
||||
|
||||
private predicate adjacentDefReachesUncertainReadExt(
|
||||
DefinitionExt def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
|
||||
) {
|
||||
@@ -390,19 +384,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value defined at SSA definition `def` can reach a read at `read`,
|
||||
* without passing through any other non-pseudo read.
|
||||
*/
|
||||
cached
|
||||
predicate firstReadExt(DefinitionExt def, VariableReadAccessCfgNode read) {
|
||||
exists(Cfg::BasicBlock bb1, int i1, Cfg::BasicBlock bb2, int i2 |
|
||||
def.definesAt(_, bb1, i1, _) and
|
||||
adjacentDefSkipUncertainReadsExt(def, bb1, i1, bb2, i2) and
|
||||
read = bb2.getNode(i2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the read at `read2` is a read of the same SSA definition `def`
|
||||
* as the read at `read1`, and `read2` can be reached from `read1` without
|
||||
@@ -420,23 +401,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the read at `read2` is a read of the same SSA definition `def`
|
||||
* as the read at `read1`, and `read2` can be reached from `read1` without
|
||||
* passing through another non-pseudo read.
|
||||
*/
|
||||
cached
|
||||
predicate adjacentReadPairExt(
|
||||
DefinitionExt def, VariableReadAccessCfgNode read1, VariableReadAccessCfgNode read2
|
||||
) {
|
||||
exists(Cfg::BasicBlock bb1, int i1, Cfg::BasicBlock bb2, int i2 |
|
||||
read1 = bb1.getNode(i1) and
|
||||
variableReadActual(bb1, i1, _) and
|
||||
adjacentDefSkipUncertainReadsExt(def, bb1, i1, bb2, i2) and
|
||||
read2 = bb2.getNode(i2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the read of `def` at `read` may be a last read. That is, `read`
|
||||
* can either reach another definition of the underlying source variable or
|
||||
@@ -451,32 +415,42 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the reference to `def` at index `i` in basic block `bb` can reach
|
||||
* another definition `next` of the same underlying source variable, without
|
||||
* passing through another write or non-pseudo read.
|
||||
*
|
||||
* The reference is either a read of `def` or `def` itself.
|
||||
*/
|
||||
cached
|
||||
predicate lastRefBeforeRedefExt(
|
||||
DefinitionExt def, Cfg::BasicBlock bb, int i, Cfg::BasicBlock input, DefinitionExt next
|
||||
) {
|
||||
exists(LocalVariable v |
|
||||
Impl::lastRefRedefExt(def, v, bb, i, input, next) and
|
||||
not SsaInput::variableRead(bb, i, v, false)
|
||||
)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb0, int i0 |
|
||||
Impl::lastRefRedefExt(def, _, bb0, i0, input, next) and
|
||||
adjacentDefReachesUncertainReadExt(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
|
||||
Impl::uncertainWriteDefinitionInput(def, result)
|
||||
}
|
||||
|
||||
cached
|
||||
module DataFlowIntegration {
|
||||
import DataFlowIntegrationImpl
|
||||
|
||||
cached
|
||||
predicate localFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
DataFlowIntegrationImpl::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate localMustFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
DataFlowIntegrationImpl::localMustFlowStep(def, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
signature predicate guardChecksSig(Cfg::CfgNodes::AstCfgNode g, Cfg::CfgNode e, boolean branch);
|
||||
|
||||
cached // nothing is actually cached
|
||||
module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
private predicate guardChecksAdjTypes(
|
||||
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e, boolean branch
|
||||
) {
|
||||
guardChecks(g, e, branch)
|
||||
}
|
||||
|
||||
private Node getABarrierNodeImpl() {
|
||||
result = DataFlowIntegrationImpl::BarrierGuard<guardChecksAdjTypes/3>::getABarrierNode()
|
||||
}
|
||||
|
||||
predicate getABarrierNode = getABarrierNodeImpl/0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -494,8 +468,7 @@ class DefinitionExt extends Impl::DefinitionExt {
|
||||
|
||||
override string toString() { result = this.(Ssa::Definition).toString() }
|
||||
|
||||
/** Gets the location of this definition. */
|
||||
Location getLocation() { result = this.(Ssa::Definition).getLocation() }
|
||||
override Location getLocation() { result = this.(Ssa::Definition).getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -506,5 +479,99 @@ class DefinitionExt extends Impl::DefinitionExt {
|
||||
class PhiReadNode extends DefinitionExt, Impl::PhiReadNode {
|
||||
override string toString() { result = "SSA phi read(" + this.getSourceVariable() + ")" }
|
||||
|
||||
override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
override Location getLocation() { result = Impl::PhiReadNode.super.getLocation() }
|
||||
}
|
||||
|
||||
class NormalParameter extends Parameter {
|
||||
NormalParameter() {
|
||||
this instanceof SimpleParameter or
|
||||
this instanceof OptionalParameter or
|
||||
this instanceof KeywordParameter or
|
||||
this instanceof HashSplatParameter or
|
||||
this instanceof SplatParameter or
|
||||
this instanceof BlockParameter
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the SSA definition node corresponding to parameter `p`. */
|
||||
pragma[nomagic]
|
||||
DefinitionExt getParameterDef(NamedParameter p) {
|
||||
exists(Cfg::BasicBlock bb, int i |
|
||||
bb.getNode(i).getAstNode() = p.getDefiningAccess() and
|
||||
result.definesAt(_, bb, i, _)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TParameterExt =
|
||||
TNormalParameter(NormalParameter p) or
|
||||
TSelfMethodParameter(MethodBase m) or
|
||||
TSelfToplevelParameter(Toplevel t)
|
||||
|
||||
/** A normal parameter or an implicit `self` parameter. */
|
||||
class ParameterExt extends TParameterExt {
|
||||
NormalParameter asParameter() { this = TNormalParameter(result) }
|
||||
|
||||
MethodBase asMethodSelf() { this = TSelfMethodParameter(result) }
|
||||
|
||||
Toplevel asToplevelSelf() { this = TSelfToplevelParameter(result) }
|
||||
|
||||
predicate isInitializedBy(WriteDefinition def) {
|
||||
def = getParameterDef(this.asParameter())
|
||||
or
|
||||
def.(Ssa::SelfDefinition).getSourceVariable().getDeclaringScope() =
|
||||
[this.asMethodSelf().(Scope), this.asToplevelSelf()]
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result =
|
||||
[
|
||||
this.asParameter().toString(), this.asMethodSelf().toString(),
|
||||
this.asToplevelSelf().toString()
|
||||
]
|
||||
}
|
||||
|
||||
Location getLocation() {
|
||||
result =
|
||||
[
|
||||
this.asParameter().getLocation(), this.asMethodSelf().getLocation(),
|
||||
this.asToplevelSelf().getLocation()
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig {
|
||||
private import codeql.ruby.controlflow.internal.Guards as Guards
|
||||
|
||||
class Parameter = ParameterExt;
|
||||
|
||||
class Expr extends Cfg::CfgNodes::ExprCfgNode {
|
||||
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
Expr getARead(Definition def) { result = Cached::getARead(def) }
|
||||
|
||||
predicate ssaDefAssigns(WriteDefinition def, Expr value) {
|
||||
def.(Ssa::WriteDefinition).assigns(value)
|
||||
}
|
||||
|
||||
predicate ssaDefInitializesParam(WriteDefinition def, Parameter p) { p.isInitializedBy(def) }
|
||||
|
||||
class Guard extends Cfg::CfgNodes::AstCfgNode {
|
||||
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
|
||||
predicate guardControlsBlock(Guard guard, SsaInput::BasicBlock bb, boolean branch) {
|
||||
Guards::guardControlsBlock(guard, bb, branch)
|
||||
}
|
||||
|
||||
/** Gets an immediate conditional successor of basic block `bb`, if any. */
|
||||
SsaInput::BasicBlock getAConditionalBasicBlockSuccessor(SsaInput::BasicBlock bb, boolean branch) {
|
||||
exists(Cfg::SuccessorTypes::ConditionalSuccessor s |
|
||||
result = bb.getASuccessor(s) and
|
||||
s.getValue() = branch
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module DataFlowIntegrationImpl = Impl::DataFlowIntegration<DataFlowIntegrationInput>;
|
||||
|
||||
@@ -5,6 +5,7 @@ private import codeql.ruby.CFG
|
||||
private import codeql.ruby.DataFlow
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import codeql.ruby.dataflow.SSA
|
||||
private import SsaImpl as SsaImpl
|
||||
|
||||
/**
|
||||
* Holds if `node` should be a sanitizer in all global taint flow configurations
|
||||
@@ -89,7 +90,7 @@ private module Cached {
|
||||
clause = case.getBranch(_) and
|
||||
def = nodeTo.(SsaDefinitionExtNode).getDefinitionExt() and
|
||||
def.getControlFlowNode() = variablesInPattern(clause.getPattern()) and
|
||||
not LocalFlow::ssaDefAssigns(def, value)
|
||||
not def.(Ssa::WriteDefinition).assigns(value)
|
||||
)
|
||||
or
|
||||
// operation involving `nodeFrom`
|
||||
|
||||
@@ -29,7 +29,7 @@ class NetHttpRequest extends Http::Client::Request::Range, DataFlow::CallNode {
|
||||
this = request
|
||||
|
|
||||
// Net::HTTP.get(...)
|
||||
method = "get" and
|
||||
method in ["get", "get_response"] and
|
||||
requestNode = API::getTopLevelMember("Net").getMember("HTTP").getReturn(method) and
|
||||
returnsResponseBody = true
|
||||
or
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "use of a broken or weak cryptographic hashing algorithm on sensitive data"
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
|
||||
private import ruby
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.security.SensitiveActions
|
||||
private import codeql.ruby.dataflow.BarrierGuards
|
||||
private import codeql.ruby.dataflow.SSA
|
||||
|
||||
private module SensitiveDataSources {
|
||||
/**
|
||||
* A data flow source of sensitive data, such as secrets, certificates, or passwords.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `SensitiveDataSource::Range` instead.
|
||||
*/
|
||||
class SensitiveDataSource extends DataFlow::Node instanceof SensitiveDataSource::Range {
|
||||
/**
|
||||
* Gets the classification of the sensitive data.
|
||||
*/
|
||||
SensitiveDataClassification getClassification() { result = super.getClassification() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new sources of sensitive data, such as secrets, certificates, or passwords. */
|
||||
module SensitiveDataSource {
|
||||
/**
|
||||
* A data flow source of sensitive data, such as secrets, certificates, or passwords.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `SensitiveDataSource` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the classification of the sensitive data.
|
||||
*/
|
||||
abstract SensitiveDataClassification getClassification();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a method that may return sensitive data.
|
||||
*/
|
||||
class SensitiveMethodCall extends SensitiveDataSource::Range instanceof SensitiveCall {
|
||||
override SensitiveDataClassification getClassification() {
|
||||
result = SensitiveCall.super.getClassification()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An assignment to a variable that may contain sensitive data.
|
||||
*/
|
||||
class SensitiveVariableAssignment extends SensitiveDataSource::Range, DataFlow::SsaDefinitionNode {
|
||||
SensitiveNode sensitiveNode;
|
||||
|
||||
SensitiveVariableAssignment() {
|
||||
this.getDefinition().(Ssa::WriteDefinition).getWriteAccess() = sensitiveNode.asExpr()
|
||||
}
|
||||
|
||||
override SensitiveDataClassification getClassification() {
|
||||
result = sensitiveNode.getClassification()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A read from a hash value that may return sensitive data.
|
||||
*/
|
||||
class SensitiveHashValueAccess extends SensitiveDataSource::Range instanceof SensitiveNode {
|
||||
SensitiveHashValueAccess() {
|
||||
this.asExpr() instanceof Cfg::CfgNodes::ExprNodes::ElementReferenceCfgNode
|
||||
}
|
||||
|
||||
override SensitiveDataClassification getClassification() {
|
||||
result = SensitiveNode.super.getClassification()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter node that may contain sensitive data.
|
||||
*/
|
||||
class SensitiveParameter extends SensitiveDataSource::Range, DataFlow::ParameterNode instanceof SensitiveNode
|
||||
{
|
||||
override SensitiveDataClassification getClassification() {
|
||||
result = SensitiveNode.super.getClassification()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "use of a broken or weak cryptographic hashing algorithm on sensitive data"
|
||||
* vulnerabilities on sensitive data that does NOT require computationally expensive
|
||||
* hashing, as well as extension points for adding your own.
|
||||
*
|
||||
* Also see the `ComputationallyExpensiveHashFunction` module.
|
||||
*/
|
||||
module NormalHashFunction {
|
||||
/**
|
||||
* A data flow source for "use of a broken or weak cryptographic hashing algorithm on
|
||||
* sensitive data" vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node {
|
||||
Source() { not this instanceof ComputationallyExpensiveHashFunction::Source }
|
||||
|
||||
/** Gets the classification of the sensitive data. */
|
||||
abstract string getClassification();
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow sink for "use of a broken or weak cryptographic hashing algorithm on
|
||||
* sensitive data" vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the name of the weak hashing algorithm.
|
||||
*/
|
||||
abstract string getAlgorithmName();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for "use of a broken or weak cryptographic hashing algorithm on
|
||||
* sensitive data" vulnerabilities.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A source of sensitive data, considered as a flow source.
|
||||
*/
|
||||
class SensitiveDataSourceAsSource extends Source instanceof SensitiveDataSources::SensitiveDataSource
|
||||
{
|
||||
override SensitiveDataClassification getClassification() {
|
||||
result = SensitiveDataSources::SensitiveDataSource.super.getClassification()
|
||||
}
|
||||
}
|
||||
|
||||
/** The input to a hashing operation using a weak algorithm, considered as a flow sink. */
|
||||
class WeakHashingOperationInputSink extends Sink {
|
||||
Cryptography::HashingAlgorithm algorithm;
|
||||
|
||||
WeakHashingOperationInputSink() {
|
||||
exists(Cryptography::CryptographicOperation operation |
|
||||
algorithm = operation.getAlgorithm() and
|
||||
algorithm.isWeak() and
|
||||
this = operation.getAnInput()
|
||||
)
|
||||
}
|
||||
|
||||
override string getAlgorithmName() { result = algorithm.getName() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "use of a broken or weak cryptographic hashing algorithm on sensitive data"
|
||||
* vulnerabilities on sensitive data that DOES require computationally expensive
|
||||
* hashing, as well as extension points for adding your own.
|
||||
*
|
||||
* Also see the `NormalHashFunction` module.
|
||||
*/
|
||||
module ComputationallyExpensiveHashFunction {
|
||||
/**
|
||||
* A data flow source of sensitive data that requires computationally expensive
|
||||
* hashing for "use of a broken or weak cryptographic hashing algorithm on sensitive
|
||||
* data" vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node {
|
||||
/** Gets the classification of the sensitive data. */
|
||||
abstract string getClassification();
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow sink for sensitive data that requires computationally expensive
|
||||
* hashing for "use of a broken or weak cryptographic hashing algorithm on sensitive
|
||||
* data" vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the name of the weak hashing algorithm.
|
||||
*/
|
||||
abstract string getAlgorithmName();
|
||||
|
||||
/**
|
||||
* Holds if this sink is for a computationally expensive hash function (meaning that
|
||||
* hash function is just weak in some other regard.
|
||||
*/
|
||||
abstract predicate isComputationallyExpensive();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer of sensitive data that requires computationally expensive
|
||||
* hashing for "use of a broken or weak cryptographic hashing
|
||||
* algorithm on sensitive data" vulnerabilities.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A source of passwords, considered as a flow source.
|
||||
*/
|
||||
class PasswordSourceAsSource extends Source instanceof SensitiveDataSources::SensitiveDataSource {
|
||||
PasswordSourceAsSource() {
|
||||
this.(SensitiveDataSources::SensitiveDataSource).getClassification() =
|
||||
SensitiveDataClassification::password()
|
||||
}
|
||||
|
||||
override SensitiveDataClassification getClassification() {
|
||||
result = SensitiveDataSources::SensitiveDataSource.super.getClassification()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The input to a password hashing operation using a weak algorithm, considered as a
|
||||
* flow sink.
|
||||
*/
|
||||
class WeakPasswordHashingOperationInputSink extends Sink {
|
||||
Cryptography::CryptographicAlgorithm algorithm;
|
||||
|
||||
WeakPasswordHashingOperationInputSink() {
|
||||
(
|
||||
algorithm instanceof Cryptography::PasswordHashingAlgorithm and
|
||||
algorithm.isWeak()
|
||||
or
|
||||
algorithm instanceof Cryptography::HashingAlgorithm // Note that HashingAlgorithm and PasswordHashingAlgorithm are disjoint
|
||||
) and
|
||||
exists(Cryptography::CryptographicOperation operation |
|
||||
algorithm = operation.getAlgorithm() and
|
||||
this = operation.getAnInput()
|
||||
)
|
||||
}
|
||||
|
||||
override string getAlgorithmName() { result = algorithm.getName() }
|
||||
|
||||
override predicate isComputationallyExpensive() {
|
||||
algorithm instanceof Cryptography::PasswordHashingAlgorithm
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting use of a broken or weak
|
||||
* cryptographic hashing algorithm on sensitive data.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `WeakSensitiveDataHashing::Configuration` is needed, otherwise
|
||||
* `WeakSensitiveDataHashingCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
private import ruby
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.TaintTracking
|
||||
private import codeql.ruby.dataflow.RemoteFlowSources
|
||||
private import codeql.ruby.dataflow.BarrierGuards
|
||||
private import codeql.ruby.security.SensitiveActions
|
||||
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting use of a broken or weak
|
||||
* cryptographic hash function on sensitive data, that does NOT require a
|
||||
* computationally expensive hash function.
|
||||
*/
|
||||
module NormalHashFunction {
|
||||
import WeakSensitiveDataHashingCustomizations::NormalHashFunction
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/** Global taint-tracking for detecting "use of a broken or weak cryptographic hashing algorithm on sensitive data" vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting use of a broken or weak
|
||||
* cryptographic hashing algorithm on passwords.
|
||||
*
|
||||
* Passwords has stricter requirements on the hashing algorithm used (must be
|
||||
* computationally expensive to prevent brute-force attacks).
|
||||
*/
|
||||
module ComputationallyExpensiveHashFunction {
|
||||
import WeakSensitiveDataHashingCustomizations::ComputationallyExpensiveHashFunction
|
||||
|
||||
/**
|
||||
* Passwords has stricter requirements on the hashing algorithm used (must be
|
||||
* computationally expensive to prevent brute-force attacks).
|
||||
*/
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/** Global taint-tracking for detecting "use of a broken or weak cryptographic hashing algorithm on passwords" vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global taint-tracking for detecting both variants of "use of a broken or weak
|
||||
* cryptographic hashing algorithm on sensitive data" vulnerabilities.
|
||||
*
|
||||
* See convenience predicates `normalHashFunctionFlowPath` and
|
||||
* `computationallyExpensiveHashFunctionFlowPath`.
|
||||
*/
|
||||
module WeakSensitiveDataHashingFlow =
|
||||
DataFlow::MergePathGraph<NormalHashFunction::Flow::PathNode,
|
||||
ComputationallyExpensiveHashFunction::Flow::PathNode, NormalHashFunction::Flow::PathGraph,
|
||||
ComputationallyExpensiveHashFunction::Flow::PathGraph>;
|
||||
|
||||
/** Holds if data can flow from `source` to `sink` with `NormalHashFunction::Flow`. */
|
||||
predicate normalHashFunctionFlowPath(
|
||||
WeakSensitiveDataHashingFlow::PathNode source, WeakSensitiveDataHashingFlow::PathNode sink
|
||||
) {
|
||||
NormalHashFunction::Flow::flowPath(source.asPathNode1(), sink.asPathNode1())
|
||||
}
|
||||
|
||||
/** Holds if data can flow from `source` to `sink` with `ComputationallyExpensiveHashFunction::Flow`. */
|
||||
predicate computationallyExpensiveHashFunctionFlowPath(
|
||||
WeakSensitiveDataHashingFlow::PathNode source, WeakSensitiveDataHashingFlow::PathNode sink
|
||||
) {
|
||||
ComputationallyExpensiveHashFunction::Flow::flowPath(source.asPathNode2(), sink.asPathNode2())
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/ruby-all
|
||||
version: 1.0.2-dev
|
||||
version: 1.0.6-dev
|
||||
groups: ruby
|
||||
extractor: ruby
|
||||
dbscheme: ruby.dbscheme
|
||||
|
||||
@@ -569,6 +569,13 @@ ruby_do_block_def(
|
||||
unique int id: @ruby_do_block
|
||||
);
|
||||
|
||||
@ruby_element_reference_block_type = @ruby_block | @ruby_do_block
|
||||
|
||||
ruby_element_reference_block(
|
||||
unique int ruby_element_reference: @ruby_element_reference ref,
|
||||
unique int block: @ruby_element_reference_block_type ref
|
||||
);
|
||||
|
||||
@ruby_element_reference_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression
|
||||
|
||||
#keyset[ruby_element_reference, index]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add `ruby_element_reference_block` DB relation
|
||||
compatibility: backwards
|
||||
@@ -1,3 +1,21 @@
|
||||
## 1.1.0
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `rb/weak-sensitive-data-hashing`, to detect cases where sensitive data is hashed using a weak cryptographic hashing algorithm.
|
||||
|
||||
## 1.0.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
ruby/ql/src/change-notes/released/1.0.2.md
Normal file
3
ruby/ql/src/change-notes/released/1.0.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.2
|
||||
|
||||
No user-facing changes.
|
||||
3
ruby/ql/src/change-notes/released/1.0.3.md
Normal file
3
ruby/ql/src/change-notes/released/1.0.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.3
|
||||
|
||||
No user-facing changes.
|
||||
3
ruby/ql/src/change-notes/released/1.0.4.md
Normal file
3
ruby/ql/src/change-notes/released/1.0.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.4
|
||||
|
||||
No user-facing changes.
|
||||
5
ruby/ql/src/change-notes/released/1.1.0.md
Normal file
5
ruby/ql/src/change-notes/released/1.1.0.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 1.1.0
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `rb/weak-sensitive-data-hashing`, to detect cases where sensitive data is hashed using a weak cryptographic hashing algorithm.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.1
|
||||
lastReleaseVersion: 1.1.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/ruby-queries
|
||||
version: 1.0.2-dev
|
||||
version: 1.1.1-dev
|
||||
groups:
|
||||
- ruby
|
||||
- queries
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Using a broken or weak cryptographic hash function can leave data
|
||||
vulnerable, and should not be used in security related code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A strong cryptographic hash function should be resistant to:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
pre-image attacks: if you know a hash value <code>h(x)</code>,
|
||||
you should not be able to easily find the input <code>x</code>.
|
||||
</li>
|
||||
<li>
|
||||
collision attacks: if you know a hash value <code>h(x)</code>,
|
||||
you should not be able to easily find a different input <code>y</code>
|
||||
with the same hash value <code>h(x) = h(y)</code>.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
In cases with a limited input space, such as for passwords, the hash
|
||||
function also needs to be computationally expensive to be resistant to
|
||||
brute-force attacks. Passwords should also have an unique salt applied
|
||||
before hashing, but that is not considered by this query.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As an example, both MD5 and SHA-1 are known to be vulnerable to collision attacks.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Since it's OK to use a weak cryptographic hash function in a non-security
|
||||
context, this query only alerts when these are used to hash sensitive
|
||||
data (such as passwords, certificates, usernames).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Use of broken or weak cryptographic algorithms that are not hashing algorithms, is
|
||||
handled by the <code>rb/weak-cryptographic-algorithm</code> query.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Ensure that you use a strong, modern cryptographic hash function:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
such as Argon2, scrypt, bcrypt, or PBKDF2 for passwords and other data with limited input space.
|
||||
</li>
|
||||
<li>
|
||||
such as SHA-2, or SHA-3 in other cases.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following example shows two functions for checking whether the hash
|
||||
of a certificate matches a known value -- to prevent tampering.
|
||||
|
||||
The first function uses MD5 that is known to be vulnerable to collision attacks.
|
||||
|
||||
The second function uses SHA-256 that is a strong cryptographic hashing function.
|
||||
</p>
|
||||
|
||||
<sample src="examples/weak_certificate_hashing.rb" />
|
||||
|
||||
</example>
|
||||
<example>
|
||||
<p>
|
||||
The following example shows two functions for hashing passwords.
|
||||
|
||||
The first function uses SHA-256 to hash passwords. Although SHA-256 is a
|
||||
strong cryptographic hash function, it is not suitable for password
|
||||
hashing since it is not computationally expensive.
|
||||
</p>
|
||||
|
||||
<sample src="examples/weak_password_hashing_bad.rb" />
|
||||
|
||||
|
||||
<p>
|
||||
The second function uses Argon2 (through the <code>argon2</code>
|
||||
gem), which is a strong password hashing algorithm (and
|
||||
includes a per-password salt by default).
|
||||
</p>
|
||||
|
||||
<sample src="examples/weak_password_hashing_good.rb" />
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html">Password Storage Cheat Sheet</a></li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @name Use of a broken or weak cryptographic hashing algorithm on sensitive data
|
||||
* @description Using broken or weak cryptographic hashing algorithms can compromise security.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.5
|
||||
* @precision high
|
||||
* @id rb/weak-sensitive-data-hashing
|
||||
* @tags security
|
||||
* external/cwe/cwe-327
|
||||
* external/cwe/cwe-328
|
||||
* external/cwe/cwe-916
|
||||
*/
|
||||
|
||||
import ruby
|
||||
import codeql.ruby.security.WeakSensitiveDataHashingQuery
|
||||
import WeakSensitiveDataHashingFlow::PathGraph
|
||||
|
||||
from
|
||||
WeakSensitiveDataHashingFlow::PathNode source, WeakSensitiveDataHashingFlow::PathNode sink,
|
||||
string ending, string algorithmName, string classification
|
||||
where
|
||||
normalHashFunctionFlowPath(source, sink) and
|
||||
algorithmName = sink.getNode().(NormalHashFunction::Sink).getAlgorithmName() and
|
||||
classification = source.getNode().(NormalHashFunction::Source).getClassification() and
|
||||
ending = "."
|
||||
or
|
||||
computationallyExpensiveHashFunctionFlowPath(source, sink) and
|
||||
algorithmName = sink.getNode().(ComputationallyExpensiveHashFunction::Sink).getAlgorithmName() and
|
||||
classification =
|
||||
source.getNode().(ComputationallyExpensiveHashFunction::Source).getClassification() and
|
||||
(
|
||||
sink.getNode().(ComputationallyExpensiveHashFunction::Sink).isComputationallyExpensive() and
|
||||
ending = "."
|
||||
or
|
||||
not sink.getNode().(ComputationallyExpensiveHashFunction::Sink).isComputationallyExpensive() and
|
||||
ending =
|
||||
" for " + classification +
|
||||
" hashing, since it is not a computationally expensive hash function."
|
||||
)
|
||||
select sink.getNode(), source, sink,
|
||||
"$@ is used in a hashing algorithm (" + algorithmName + ") that is insecure" + ending,
|
||||
source.getNode(), "Sensitive data (" + classification + ")"
|
||||
@@ -0,0 +1,11 @@
|
||||
require 'openssl'
|
||||
|
||||
def certificate_matches_known_hash_bad(certificate, known_hash)
|
||||
hash = OpenSSL::Digest.new('SHA1').digest certificate
|
||||
hash == known_hash
|
||||
end
|
||||
|
||||
def certificate_matches_known_hash_good(certificate, known_hash)
|
||||
hash = OpenSSL::Digest.new('SHA256').digest certificate
|
||||
hash == known_hash
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
require 'openssl'
|
||||
|
||||
def get_password_hash(password, salt)
|
||||
OpenSSL::Digest.new('SHA256').digest(password + salt) # BAD
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
require 'argon2'
|
||||
|
||||
def get_initial_hash(password)
|
||||
Argon2::Password.create(password)
|
||||
end
|
||||
|
||||
def check_password(password, known_hash)
|
||||
Argon2::Password.verify_password(password, known_hash)
|
||||
end
|
||||
@@ -1,6 +1,10 @@
|
||||
testFailures
|
||||
edges
|
||||
| blocks.rb:14:12:14:20 | call to source | blocks.rb:8:10:8:14 | yield ... | provenance | |
|
||||
| blocks.rb:17:10:17:10 | x | blocks.rb:18:11:18:11 | x | provenance | |
|
||||
| blocks.rb:18:11:18:11 | x | blocks.rb:24:18:24:18 | x | provenance | |
|
||||
| blocks.rb:24:3:24:11 | call to source | blocks.rb:17:10:17:10 | x | provenance | |
|
||||
| blocks.rb:24:18:24:18 | x | blocks.rb:25:8:25:8 | x | provenance | |
|
||||
| captured_variables.rb:9:24:9:24 | x | captured_variables.rb:11:5:11:6 | fn [captured x] | provenance | |
|
||||
| captured_variables.rb:11:5:11:6 | fn [captured x] | captured_variables.rb:10:20:10:20 | x | provenance | |
|
||||
| captured_variables.rb:13:20:13:29 | call to taint | captured_variables.rb:9:24:9:24 | x | provenance | |
|
||||
@@ -254,6 +258,11 @@ edges
|
||||
nodes
|
||||
| blocks.rb:8:10:8:14 | yield ... | semmle.label | yield ... |
|
||||
| blocks.rb:14:12:14:20 | call to source | semmle.label | call to source |
|
||||
| blocks.rb:17:10:17:10 | x | semmle.label | x |
|
||||
| blocks.rb:18:11:18:11 | x | semmle.label | x |
|
||||
| blocks.rb:24:3:24:11 | call to source | semmle.label | call to source |
|
||||
| blocks.rb:24:18:24:18 | x | semmle.label | x |
|
||||
| blocks.rb:25:8:25:8 | x | semmle.label | x |
|
||||
| captured_variables.rb:9:24:9:24 | x | semmle.label | x |
|
||||
| captured_variables.rb:10:20:10:20 | x | semmle.label | x |
|
||||
| captured_variables.rb:11:5:11:6 | fn [captured x] | semmle.label | fn [captured x] |
|
||||
@@ -554,6 +563,7 @@ subpaths
|
||||
| instance_variables.rb:120:6:120:10 | foo16 [@field] | instance_variables.rb:13:5:15:7 | self in get_field [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:120:6:120:20 | call to get_field |
|
||||
#select
|
||||
| blocks.rb:8:10:8:14 | yield ... | blocks.rb:14:12:14:20 | call to source | blocks.rb:8:10:8:14 | yield ... | $@ | blocks.rb:14:12:14:20 | call to source | call to source |
|
||||
| blocks.rb:25:8:25:8 | x | blocks.rb:24:3:24:11 | call to source | blocks.rb:25:8:25:8 | x | $@ | blocks.rb:24:3:24:11 | call to source | call to source |
|
||||
| captured_variables.rb:10:20:10:20 | x | captured_variables.rb:13:20:13:29 | call to taint | captured_variables.rb:10:20:10:20 | x | $@ | captured_variables.rb:13:20:13:29 | call to taint | call to taint |
|
||||
| captured_variables.rb:17:14:17:14 | x | captured_variables.rb:20:25:20:34 | call to taint | captured_variables.rb:17:14:17:14 | x | $@ | captured_variables.rb:20:25:20:34 | call to taint | call to taint |
|
||||
| captured_variables.rb:24:14:24:14 | x | captured_variables.rb:27:48:27:57 | call to taint | captured_variables.rb:24:14:24:14 | x | $@ | captured_variables.rb:27:48:27:57 | call to taint | call to taint |
|
||||
|
||||
@@ -12,3 +12,15 @@ end
|
||||
A.new.m1 { source(1) }
|
||||
|
||||
A.new.m2 { source(2) }
|
||||
|
||||
class B
|
||||
def [](x)
|
||||
yield x
|
||||
end
|
||||
end
|
||||
|
||||
b = B.new
|
||||
|
||||
b[source(3)] do |x|
|
||||
sink x # $ hasValueFlow=3
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,14 +10,14 @@ edges
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:26:31:26:37 | tainted | provenance | |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:30:24:30:30 | tainted | provenance | |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:31:27:31:33 | tainted | provenance | |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:34:16:34:22 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:34:16:34:22 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:35:16:35:22 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:35:16:35:22 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:36:21:36:27 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:36:21:36:27 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:37:36:37:42 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:37:36:37:42 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:34:16:34:22 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:34:16:34:22 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:35:16:35:22 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:35:16:35:22 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:36:21:36:27 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:36:21:36:27 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:37:36:37:42 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:37:36:37:42 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:51:24:51:30 | tainted | provenance | |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:56:22:56:28 | tainted | provenance | |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:57:17:57:23 | tainted | provenance | |
|
||||
@@ -27,30 +27,30 @@ edges
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:122:16:122:22 | tainted | provenance | |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:128:14:128:20 | tainted | provenance | |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:131:16:131:22 | tainted | provenance | |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:131:16:131:22 | tainted | provenance | Sink:MaD:3 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:131:16:131:22 | tainted | provenance | Sink:MaD:3 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:132:21:132:27 | tainted | provenance | Sink:MaD:3 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:132:21:132:27 | tainted | provenance | Sink:MaD:3 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:135:26:135:32 | tainted | provenance | Sink:MaD:4 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:135:26:135:32 | tainted | provenance | Sink:MaD:4 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:137:23:137:29 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:137:23:137:29 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:140:19:140:25 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:140:19:140:25 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:141:19:141:25 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:141:19:141:25 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:145:26:145:32 | tainted | provenance | Sink:MaD:1 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:145:26:145:32 | tainted | provenance | Sink:MaD:1 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:147:16:147:22 | tainted | provenance | Sink:MaD:0 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:147:16:147:22 | tainted | provenance | Sink:MaD:0 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:150:39:150:45 | tainted | provenance | Sink:MaD:2 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:150:39:150:45 | tainted | provenance | Sink:MaD:2 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:154:20:154:26 | tainted | provenance | Sink:MaD:5 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:154:20:154:26 | tainted | provenance | Sink:MaD:5 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:155:28:155:34 | tainted | provenance | Sink:MaD:5 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:155:28:155:34 | tainted | provenance | Sink:MaD:5 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:156:27:156:33 | tainted | provenance | Sink:MaD:5 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:156:27:156:33 | tainted | provenance | Sink:MaD:5 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:131:16:131:22 | tainted | provenance | Sink:MaD:65 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:131:16:131:22 | tainted | provenance | Sink:MaD:65 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:132:21:132:27 | tainted | provenance | Sink:MaD:65 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:132:21:132:27 | tainted | provenance | Sink:MaD:65 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:135:26:135:32 | tainted | provenance | Sink:MaD:66 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:135:26:135:32 | tainted | provenance | Sink:MaD:66 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:137:23:137:29 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:137:23:137:29 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:140:19:140:25 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:140:19:140:25 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:141:19:141:25 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:141:19:141:25 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:145:26:145:32 | tainted | provenance | Sink:MaD:63 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:145:26:145:32 | tainted | provenance | Sink:MaD:63 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:147:16:147:22 | tainted | provenance | Sink:MaD:62 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:147:16:147:22 | tainted | provenance | Sink:MaD:62 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:150:39:150:45 | tainted | provenance | Sink:MaD:64 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:150:39:150:45 | tainted | provenance | Sink:MaD:64 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:154:20:154:26 | tainted | provenance | Sink:MaD:67 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:154:20:154:26 | tainted | provenance | Sink:MaD:67 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:155:28:155:34 | tainted | provenance | Sink:MaD:67 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:155:28:155:34 | tainted | provenance | Sink:MaD:67 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:156:27:156:33 | tainted | provenance | Sink:MaD:67 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:156:27:156:33 | tainted | provenance | Sink:MaD:67 |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:157:14:160:3 | do ... end [captured tainted] | provenance | |
|
||||
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:157:14:160:3 | do ... end [captured tainted] | provenance | |
|
||||
| summaries.rb:1:20:1:36 | call to source | summaries.rb:1:11:1:36 | call to identity | provenance | |
|
||||
@@ -81,34 +81,34 @@ edges
|
||||
| summaries.rb:16:36:16:42 | tainted | summaries.rb:16:12:16:43 | call to apply_lambda | provenance | |
|
||||
| summaries.rb:20:1:20:8 | tainted4 | summaries.rb:21:6:21:13 | tainted4 | provenance | |
|
||||
| summaries.rb:20:12:20:32 | call to firstArg | summaries.rb:20:1:20:8 | tainted4 | provenance | |
|
||||
| summaries.rb:20:25:20:31 | tainted | summaries.rb:20:12:20:32 | call to firstArg | provenance | MaD:11 |
|
||||
| summaries.rb:20:25:20:31 | tainted | summaries.rb:20:12:20:32 | call to firstArg | provenance | MaD:73 |
|
||||
| summaries.rb:26:1:26:8 | tainted5 | summaries.rb:27:6:27:13 | tainted5 | provenance | |
|
||||
| summaries.rb:26:12:26:38 | call to secondArg | summaries.rb:26:1:26:8 | tainted5 | provenance | |
|
||||
| summaries.rb:26:31:26:37 | tainted | summaries.rb:26:12:26:38 | call to secondArg | provenance | MaD:17 |
|
||||
| summaries.rb:30:24:30:30 | tainted | summaries.rb:30:6:30:42 | call to onlyWithBlock | provenance | MaD:15 |
|
||||
| summaries.rb:31:27:31:33 | tainted | summaries.rb:31:6:31:34 | call to onlyWithoutBlock | provenance | MaD:16 |
|
||||
| summaries.rb:26:31:26:37 | tainted | summaries.rb:26:12:26:38 | call to secondArg | provenance | MaD:79 |
|
||||
| summaries.rb:30:24:30:30 | tainted | summaries.rb:30:6:30:42 | call to onlyWithBlock | provenance | MaD:77 |
|
||||
| summaries.rb:31:27:31:33 | tainted | summaries.rb:31:6:31:34 | call to onlyWithoutBlock | provenance | MaD:78 |
|
||||
| summaries.rb:40:3:40:3 | t | summaries.rb:41:24:41:24 | t | provenance | |
|
||||
| summaries.rb:40:3:40:3 | t | summaries.rb:42:24:42:24 | t | provenance | |
|
||||
| summaries.rb:40:3:40:3 | t | summaries.rb:44:8:44:8 | t | provenance | |
|
||||
| summaries.rb:40:7:40:17 | call to source | summaries.rb:40:3:40:3 | t | provenance | |
|
||||
| summaries.rb:41:24:41:24 | t | summaries.rb:41:8:41:25 | call to matchedByName | provenance | MaD:24 |
|
||||
| summaries.rb:42:24:42:24 | t | summaries.rb:42:8:42:25 | call to matchedByName | provenance | MaD:24 |
|
||||
| summaries.rb:44:8:44:8 | t | summaries.rb:44:8:44:27 | call to matchedByNameRcv | provenance | MaD:23 |
|
||||
| summaries.rb:48:24:48:41 | call to source | summaries.rb:48:8:48:42 | call to preserveTaint | provenance | MaD:10 |
|
||||
| summaries.rb:51:24:51:30 | tainted | summaries.rb:51:6:51:31 | call to namedArg | provenance | MaD:14 |
|
||||
| summaries.rb:41:24:41:24 | t | summaries.rb:41:8:41:25 | call to matchedByName | provenance | MaD:86 |
|
||||
| summaries.rb:42:24:42:24 | t | summaries.rb:42:8:42:25 | call to matchedByName | provenance | MaD:86 |
|
||||
| summaries.rb:44:8:44:8 | t | summaries.rb:44:8:44:27 | call to matchedByNameRcv | provenance | MaD:85 |
|
||||
| summaries.rb:48:24:48:41 | call to source | summaries.rb:48:8:48:42 | call to preserveTaint | provenance | MaD:72 |
|
||||
| summaries.rb:51:24:51:30 | tainted | summaries.rb:51:6:51:31 | call to namedArg | provenance | MaD:76 |
|
||||
| summaries.rb:53:1:53:4 | args [element :foo] | summaries.rb:54:21:54:24 | args [element :foo] | provenance | |
|
||||
| summaries.rb:53:8:53:33 | call to [] [element :foo] | summaries.rb:53:1:53:4 | args [element :foo] | provenance | |
|
||||
| summaries.rb:53:15:53:31 | call to source | summaries.rb:53:8:53:33 | call to [] [element :foo] | provenance | |
|
||||
| summaries.rb:54:19:54:24 | ** ... [element :foo] | summaries.rb:54:6:54:25 | call to namedArg | provenance | MaD:14 |
|
||||
| summaries.rb:54:19:54:24 | ** ... [element :foo] | summaries.rb:54:6:54:25 | call to namedArg | provenance | MaD:76 |
|
||||
| summaries.rb:54:21:54:24 | args [element :foo] | summaries.rb:54:19:54:24 | ** ... [element :foo] | provenance | |
|
||||
| summaries.rb:56:22:56:28 | tainted | summaries.rb:56:6:56:29 | call to anyArg | provenance | MaD:7 |
|
||||
| summaries.rb:57:17:57:23 | tainted | summaries.rb:57:6:57:24 | call to anyArg | provenance | MaD:7 |
|
||||
| summaries.rb:59:27:59:33 | tainted | summaries.rb:59:6:59:34 | call to anyNamedArg | provenance | MaD:8 |
|
||||
| summaries.rb:63:32:63:38 | tainted | summaries.rb:63:6:63:39 | call to anyPositionFromOne | provenance | MaD:9 |
|
||||
| summaries.rb:65:23:65:29 | tainted | summaries.rb:65:40:65:40 | x | provenance | MaD:12 |
|
||||
| summaries.rb:56:22:56:28 | tainted | summaries.rb:56:6:56:29 | call to anyArg | provenance | MaD:69 |
|
||||
| summaries.rb:57:17:57:23 | tainted | summaries.rb:57:6:57:24 | call to anyArg | provenance | MaD:69 |
|
||||
| summaries.rb:59:27:59:33 | tainted | summaries.rb:59:6:59:34 | call to anyNamedArg | provenance | MaD:70 |
|
||||
| summaries.rb:63:32:63:38 | tainted | summaries.rb:63:6:63:39 | call to anyPositionFromOne | provenance | MaD:71 |
|
||||
| summaries.rb:65:23:65:29 | tainted | summaries.rb:65:40:65:40 | x | provenance | MaD:74 |
|
||||
| summaries.rb:65:40:65:40 | x | summaries.rb:66:8:66:8 | x | provenance | |
|
||||
| summaries.rb:73:24:73:53 | call to source | summaries.rb:73:8:73:54 | call to preserveTaint | provenance | MaD:18 |
|
||||
| summaries.rb:76:26:76:56 | call to source | summaries.rb:76:8:76:57 | call to preserveTaint | provenance | MaD:19 |
|
||||
| summaries.rb:73:24:73:53 | call to source | summaries.rb:73:8:73:54 | call to preserveTaint | provenance | MaD:80 |
|
||||
| summaries.rb:76:26:76:56 | call to source | summaries.rb:76:8:76:57 | call to preserveTaint | provenance | MaD:81 |
|
||||
| summaries.rb:79:1:79:1 | a [element 1] | summaries.rb:82:6:82:6 | a [element 1] | provenance | |
|
||||
| summaries.rb:79:1:79:1 | a [element 1] | summaries.rb:82:6:82:6 | a [element 1] | provenance | |
|
||||
| summaries.rb:79:1:79:1 | a [element 1] | summaries.rb:83:6:83:6 | a [element 1] | provenance | |
|
||||
@@ -145,12 +145,12 @@ edges
|
||||
| summaries.rb:81:1:81:1 | [post] a [element] | summaries.rb:95:1:95:1 | a [element] | provenance | |
|
||||
| summaries.rb:81:13:81:27 | call to source | summaries.rb:81:1:81:1 | [post] a [element] | provenance | |
|
||||
| summaries.rb:81:13:81:27 | call to source | summaries.rb:81:1:81:1 | [post] a [element] | provenance | |
|
||||
| summaries.rb:82:6:82:6 | a [element 1] | summaries.rb:82:6:82:24 | call to readElementOne | provenance | MaD:25 |
|
||||
| summaries.rb:82:6:82:6 | a [element 1] | summaries.rb:82:6:82:24 | call to readElementOne | provenance | MaD:25 |
|
||||
| summaries.rb:82:6:82:6 | a [element] | summaries.rb:82:6:82:24 | call to readElementOne | provenance | MaD:25 |
|
||||
| summaries.rb:82:6:82:6 | a [element] | summaries.rb:82:6:82:24 | call to readElementOne | provenance | MaD:25 |
|
||||
| summaries.rb:83:6:83:6 | a [element 1] | summaries.rb:83:6:83:31 | call to readExactlyElementOne | provenance | MaD:26 |
|
||||
| summaries.rb:83:6:83:6 | a [element 1] | summaries.rb:83:6:83:31 | call to readExactlyElementOne | provenance | MaD:26 |
|
||||
| summaries.rb:82:6:82:6 | a [element 1] | summaries.rb:82:6:82:24 | call to readElementOne | provenance | MaD:87 |
|
||||
| summaries.rb:82:6:82:6 | a [element 1] | summaries.rb:82:6:82:24 | call to readElementOne | provenance | MaD:87 |
|
||||
| summaries.rb:82:6:82:6 | a [element] | summaries.rb:82:6:82:24 | call to readElementOne | provenance | MaD:87 |
|
||||
| summaries.rb:82:6:82:6 | a [element] | summaries.rb:82:6:82:24 | call to readElementOne | provenance | MaD:87 |
|
||||
| summaries.rb:83:6:83:6 | a [element 1] | summaries.rb:83:6:83:31 | call to readExactlyElementOne | provenance | MaD:88 |
|
||||
| summaries.rb:83:6:83:6 | a [element 1] | summaries.rb:83:6:83:31 | call to readExactlyElementOne | provenance | MaD:88 |
|
||||
| summaries.rb:84:6:84:6 | a [element] | summaries.rb:84:6:84:9 | ...[...] | provenance | |
|
||||
| summaries.rb:84:6:84:6 | a [element] | summaries.rb:84:6:84:9 | ...[...] | provenance | |
|
||||
| summaries.rb:85:6:85:6 | a [element 1] | summaries.rb:85:6:85:9 | ...[...] | provenance | |
|
||||
@@ -169,10 +169,10 @@ edges
|
||||
| summaries.rb:87:1:87:1 | b [element] | summaries.rb:89:6:89:6 | b [element] | provenance | |
|
||||
| summaries.rb:87:1:87:1 | b [element] | summaries.rb:90:6:90:6 | b [element] | provenance | |
|
||||
| summaries.rb:87:1:87:1 | b [element] | summaries.rb:90:6:90:6 | b [element] | provenance | |
|
||||
| summaries.rb:87:5:87:5 | a [element 1] | summaries.rb:87:5:87:22 | call to withElementOne [element 1] | provenance | MaD:28 |
|
||||
| summaries.rb:87:5:87:5 | a [element 1] | summaries.rb:87:5:87:22 | call to withElementOne [element 1] | provenance | MaD:28 |
|
||||
| summaries.rb:87:5:87:5 | a [element] | summaries.rb:87:5:87:22 | call to withElementOne [element] | provenance | MaD:28 |
|
||||
| summaries.rb:87:5:87:5 | a [element] | summaries.rb:87:5:87:22 | call to withElementOne [element] | provenance | MaD:28 |
|
||||
| summaries.rb:87:5:87:5 | a [element 1] | summaries.rb:87:5:87:22 | call to withElementOne [element 1] | provenance | MaD:90 |
|
||||
| summaries.rb:87:5:87:5 | a [element 1] | summaries.rb:87:5:87:22 | call to withElementOne [element 1] | provenance | MaD:90 |
|
||||
| summaries.rb:87:5:87:5 | a [element] | summaries.rb:87:5:87:22 | call to withElementOne [element] | provenance | MaD:90 |
|
||||
| summaries.rb:87:5:87:5 | a [element] | summaries.rb:87:5:87:22 | call to withElementOne [element] | provenance | MaD:90 |
|
||||
| summaries.rb:87:5:87:22 | call to withElementOne [element 1] | summaries.rb:87:1:87:1 | b [element 1] | provenance | |
|
||||
| summaries.rb:87:5:87:22 | call to withElementOne [element 1] | summaries.rb:87:1:87:1 | b [element 1] | provenance | |
|
||||
| summaries.rb:87:5:87:22 | call to withElementOne [element] | summaries.rb:87:1:87:1 | b [element] | provenance | |
|
||||
@@ -187,8 +187,8 @@ edges
|
||||
| summaries.rb:90:6:90:6 | b [element] | summaries.rb:90:6:90:9 | ...[...] | provenance | |
|
||||
| summaries.rb:91:1:91:1 | c [element 1] | summaries.rb:93:6:93:6 | c [element 1] | provenance | |
|
||||
| summaries.rb:91:1:91:1 | c [element 1] | summaries.rb:93:6:93:6 | c [element 1] | provenance | |
|
||||
| summaries.rb:91:5:91:5 | a [element 1] | summaries.rb:91:5:91:29 | call to withExactlyElementOne [element 1] | provenance | MaD:29 |
|
||||
| summaries.rb:91:5:91:5 | a [element 1] | summaries.rb:91:5:91:29 | call to withExactlyElementOne [element 1] | provenance | MaD:29 |
|
||||
| summaries.rb:91:5:91:5 | a [element 1] | summaries.rb:91:5:91:29 | call to withExactlyElementOne [element 1] | provenance | MaD:91 |
|
||||
| summaries.rb:91:5:91:5 | a [element 1] | summaries.rb:91:5:91:29 | call to withExactlyElementOne [element 1] | provenance | MaD:91 |
|
||||
| summaries.rb:91:5:91:29 | call to withExactlyElementOne [element 1] | summaries.rb:91:1:91:1 | c [element 1] | provenance | |
|
||||
| summaries.rb:91:5:91:29 | call to withExactlyElementOne [element 1] | summaries.rb:91:1:91:1 | c [element 1] | provenance | |
|
||||
| summaries.rb:93:6:93:6 | c [element 1] | summaries.rb:93:6:93:9 | ...[...] | provenance | |
|
||||
@@ -203,10 +203,10 @@ edges
|
||||
| summaries.rb:95:1:95:1 | [post] a [element] | summaries.rb:97:6:97:6 | a [element] | provenance | |
|
||||
| summaries.rb:95:1:95:1 | [post] a [element] | summaries.rb:98:6:98:6 | a [element] | provenance | |
|
||||
| summaries.rb:95:1:95:1 | [post] a [element] | summaries.rb:98:6:98:6 | a [element] | provenance | |
|
||||
| summaries.rb:95:1:95:1 | a [element 2] | summaries.rb:95:1:95:1 | [post] a [element 2] | provenance | MaD:32 |
|
||||
| summaries.rb:95:1:95:1 | a [element 2] | summaries.rb:95:1:95:1 | [post] a [element 2] | provenance | MaD:32 |
|
||||
| summaries.rb:95:1:95:1 | a [element] | summaries.rb:95:1:95:1 | [post] a [element] | provenance | MaD:32 |
|
||||
| summaries.rb:95:1:95:1 | a [element] | summaries.rb:95:1:95:1 | [post] a [element] | provenance | MaD:32 |
|
||||
| summaries.rb:95:1:95:1 | a [element 2] | summaries.rb:95:1:95:1 | [post] a [element 2] | provenance | MaD:94 |
|
||||
| summaries.rb:95:1:95:1 | a [element 2] | summaries.rb:95:1:95:1 | [post] a [element 2] | provenance | MaD:94 |
|
||||
| summaries.rb:95:1:95:1 | a [element] | summaries.rb:95:1:95:1 | [post] a [element] | provenance | MaD:94 |
|
||||
| summaries.rb:95:1:95:1 | a [element] | summaries.rb:95:1:95:1 | [post] a [element] | provenance | MaD:94 |
|
||||
| summaries.rb:96:6:96:6 | a [element] | summaries.rb:96:6:96:9 | ...[...] | provenance | |
|
||||
| summaries.rb:96:6:96:6 | a [element] | summaries.rb:96:6:96:9 | ...[...] | provenance | |
|
||||
| summaries.rb:97:6:97:6 | a [element] | summaries.rb:97:6:97:9 | ...[...] | provenance | |
|
||||
@@ -217,8 +217,8 @@ edges
|
||||
| summaries.rb:98:6:98:6 | a [element] | summaries.rb:98:6:98:9 | ...[...] | provenance | |
|
||||
| summaries.rb:99:1:99:1 | [post] a [element 2] | summaries.rb:102:6:102:6 | a [element 2] | provenance | |
|
||||
| summaries.rb:99:1:99:1 | [post] a [element 2] | summaries.rb:102:6:102:6 | a [element 2] | provenance | |
|
||||
| summaries.rb:99:1:99:1 | a [element 2] | summaries.rb:99:1:99:1 | [post] a [element 2] | provenance | MaD:31 |
|
||||
| summaries.rb:99:1:99:1 | a [element 2] | summaries.rb:99:1:99:1 | [post] a [element 2] | provenance | MaD:31 |
|
||||
| summaries.rb:99:1:99:1 | a [element 2] | summaries.rb:99:1:99:1 | [post] a [element 2] | provenance | MaD:93 |
|
||||
| summaries.rb:99:1:99:1 | a [element 2] | summaries.rb:99:1:99:1 | [post] a [element 2] | provenance | MaD:93 |
|
||||
| summaries.rb:102:6:102:6 | a [element 2] | summaries.rb:102:6:102:9 | ...[...] | provenance | |
|
||||
| summaries.rb:102:6:102:6 | a [element 2] | summaries.rb:102:6:102:9 | ...[...] | provenance | |
|
||||
| summaries.rb:103:1:103:1 | [post] d [element 3] | summaries.rb:104:1:104:1 | d [element 3] | provenance | |
|
||||
@@ -227,39 +227,39 @@ edges
|
||||
| summaries.rb:103:8:103:22 | call to source | summaries.rb:103:1:103:1 | [post] d [element 3] | provenance | |
|
||||
| summaries.rb:104:1:104:1 | [post] d [element 3] | summaries.rb:108:6:108:6 | d [element 3] | provenance | |
|
||||
| summaries.rb:104:1:104:1 | [post] d [element 3] | summaries.rb:108:6:108:6 | d [element 3] | provenance | |
|
||||
| summaries.rb:104:1:104:1 | d [element 3] | summaries.rb:104:1:104:1 | [post] d [element 3] | provenance | MaD:30 |
|
||||
| summaries.rb:104:1:104:1 | d [element 3] | summaries.rb:104:1:104:1 | [post] d [element 3] | provenance | MaD:30 |
|
||||
| summaries.rb:104:1:104:1 | d [element 3] | summaries.rb:104:1:104:1 | [post] d [element 3] | provenance | MaD:92 |
|
||||
| summaries.rb:104:1:104:1 | d [element 3] | summaries.rb:104:1:104:1 | [post] d [element 3] | provenance | MaD:92 |
|
||||
| summaries.rb:108:6:108:6 | d [element 3] | summaries.rb:108:6:108:9 | ...[...] | provenance | |
|
||||
| summaries.rb:108:6:108:6 | d [element 3] | summaries.rb:108:6:108:9 | ...[...] | provenance | |
|
||||
| summaries.rb:111:1:111:1 | [post] x [@value] | summaries.rb:112:6:112:6 | x [@value] | provenance | |
|
||||
| summaries.rb:111:1:111:1 | [post] x [@value] | summaries.rb:112:6:112:6 | x [@value] | provenance | |
|
||||
| summaries.rb:111:13:111:26 | call to source | summaries.rb:111:1:111:1 | [post] x [@value] | provenance | MaD:27 |
|
||||
| summaries.rb:111:13:111:26 | call to source | summaries.rb:111:1:111:1 | [post] x [@value] | provenance | MaD:27 |
|
||||
| summaries.rb:112:6:112:6 | x [@value] | summaries.rb:112:6:112:16 | call to get_value | provenance | MaD:22 |
|
||||
| summaries.rb:112:6:112:6 | x [@value] | summaries.rb:112:6:112:16 | call to get_value | provenance | MaD:22 |
|
||||
| summaries.rb:111:13:111:26 | call to source | summaries.rb:111:1:111:1 | [post] x [@value] | provenance | MaD:89 |
|
||||
| summaries.rb:111:13:111:26 | call to source | summaries.rb:111:1:111:1 | [post] x [@value] | provenance | MaD:89 |
|
||||
| summaries.rb:112:6:112:6 | x [@value] | summaries.rb:112:6:112:16 | call to get_value | provenance | MaD:84 |
|
||||
| summaries.rb:112:6:112:6 | x [@value] | summaries.rb:112:6:112:16 | call to get_value | provenance | MaD:84 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:128:14:128:20 | tainted | provenance | |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:131:16:131:22 | tainted | provenance | |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:131:16:131:22 | tainted | provenance | Sink:MaD:3 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:132:21:132:27 | tainted | provenance | Sink:MaD:3 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:135:26:135:32 | tainted | provenance | Sink:MaD:4 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:137:23:137:29 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:140:19:140:25 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:141:19:141:25 | tainted | provenance | Sink:MaD:6 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:145:26:145:32 | tainted | provenance | Sink:MaD:1 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:147:16:147:22 | tainted | provenance | Sink:MaD:0 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:150:39:150:45 | tainted | provenance | Sink:MaD:2 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:154:20:154:26 | tainted | provenance | Sink:MaD:5 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:155:28:155:34 | tainted | provenance | Sink:MaD:5 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:156:27:156:33 | tainted | provenance | Sink:MaD:5 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:131:16:131:22 | tainted | provenance | Sink:MaD:65 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:132:21:132:27 | tainted | provenance | Sink:MaD:65 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:135:26:135:32 | tainted | provenance | Sink:MaD:66 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:137:23:137:29 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:140:19:140:25 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:141:19:141:25 | tainted | provenance | Sink:MaD:68 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:145:26:145:32 | tainted | provenance | Sink:MaD:63 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:147:16:147:22 | tainted | provenance | Sink:MaD:62 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:150:39:150:45 | tainted | provenance | Sink:MaD:64 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:154:20:154:26 | tainted | provenance | Sink:MaD:67 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:155:28:155:34 | tainted | provenance | Sink:MaD:67 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:156:27:156:33 | tainted | provenance | Sink:MaD:67 |
|
||||
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:157:14:160:3 | do ... end [captured tainted] | provenance | |
|
||||
| summaries.rb:122:16:122:22 | tainted | summaries.rb:122:16:122:22 | [post] tainted | provenance | MaD:20 |
|
||||
| summaries.rb:122:16:122:22 | tainted | summaries.rb:122:25:122:25 | [post] y | provenance | MaD:20 |
|
||||
| summaries.rb:122:16:122:22 | tainted | summaries.rb:122:33:122:33 | [post] z | provenance | MaD:20 |
|
||||
| summaries.rb:122:16:122:22 | tainted | summaries.rb:122:16:122:22 | [post] tainted | provenance | MaD:82 |
|
||||
| summaries.rb:122:16:122:22 | tainted | summaries.rb:122:25:122:25 | [post] y | provenance | MaD:82 |
|
||||
| summaries.rb:122:16:122:22 | tainted | summaries.rb:122:33:122:33 | [post] z | provenance | MaD:82 |
|
||||
| summaries.rb:122:25:122:25 | [post] y | summaries.rb:124:6:124:6 | y | provenance | |
|
||||
| summaries.rb:122:33:122:33 | [post] z | summaries.rb:125:6:125:6 | z | provenance | |
|
||||
| summaries.rb:128:1:128:1 | [post] x | summaries.rb:129:6:129:6 | x | provenance | |
|
||||
| summaries.rb:128:14:128:20 | tainted | summaries.rb:128:1:128:1 | [post] x | provenance | MaD:21 |
|
||||
| summaries.rb:131:16:131:22 | tainted | summaries.rb:131:1:131:23 | synthetic splat argument | provenance | Sink:MaD:3 |
|
||||
| summaries.rb:128:14:128:20 | tainted | summaries.rb:128:1:128:1 | [post] x | provenance | MaD:83 |
|
||||
| summaries.rb:131:16:131:22 | tainted | summaries.rb:131:1:131:23 | synthetic splat argument | provenance | Sink:MaD:65 |
|
||||
| summaries.rb:157:14:160:3 | do ... end [captured tainted] | summaries.rb:158:15:158:21 | tainted | provenance | heuristic-callback |
|
||||
| summaries.rb:157:14:160:3 | do ... end [captured tainted] | summaries.rb:158:15:158:21 | tainted | provenance | heuristic-callback |
|
||||
nodes
|
||||
|
||||
@@ -154,6 +154,10 @@ calls.rb:
|
||||
# 649| CustomNew2
|
||||
#-----| super -> Object
|
||||
|
||||
element_reference.rb:
|
||||
# 1| ClassWithElementRef
|
||||
#-----| super -> Object
|
||||
|
||||
hello.rb:
|
||||
# 1| EnglishWords
|
||||
|
||||
|
||||
@@ -257,6 +257,13 @@ getTarget
|
||||
| calls.rb:659:1:659:23 | call to instance | calls.rb:654:5:656:7 | instance |
|
||||
| calls.rb:667:2:667:25 | call to capture_parameter | calls.rb:661:1:665:3 | capture_parameter |
|
||||
| calls.rb:667:20:667:25 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| element_reference.rb:3:9:3:19 | yield ... | element_reference.rb:9:6:9:19 | { ... } |
|
||||
| element_reference.rb:3:9:3:19 | yield ... | element_reference.rb:11:6:13:3 | do ... end |
|
||||
| element_reference.rb:7:5:7:27 | call to new | calls.rb:117:5:117:16 | new |
|
||||
| element_reference.rb:9:1:9:19 | ...[...] | element_reference.rb:2:5:4:7 | [] |
|
||||
| element_reference.rb:9:12:9:17 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| element_reference.rb:11:1:13:3 | ...[...] | element_reference.rb:2:5:4:7 | [] |
|
||||
| element_reference.rb:12:5:12:10 | call to puts | calls.rb:102:5:102:30 | puts |
|
||||
| hello.rb:12:5:12:24 | call to include | calls.rb:108:5:110:7 | include |
|
||||
| hello.rb:14:16:14:20 | call to hello | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:20:16:20:20 | super call to message | hello.rb:13:5:15:7 | message |
|
||||
@@ -385,6 +392,7 @@ unresolvedCall
|
||||
| calls.rb:662:5:662:11 | call to [] |
|
||||
| calls.rb:662:5:664:7 | call to each |
|
||||
| calls.rb:667:1:667:35 | call to instance |
|
||||
| element_reference.rb:3:15:3:19 | ... + ... |
|
||||
| hello.rb:20:16:20:26 | ... + ... |
|
||||
| hello.rb:20:16:20:34 | ... + ... |
|
||||
| hello.rb:20:16:20:40 | ... + ... |
|
||||
@@ -512,6 +520,7 @@ publicMethod
|
||||
| calls.rb:642:5:644:7 | new |
|
||||
| calls.rb:650:5:652:7 | new |
|
||||
| calls.rb:654:5:656:7 | instance |
|
||||
| element_reference.rb:2:5:4:7 | [] |
|
||||
| hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:5:5:7:7 | world |
|
||||
| hello.rb:13:5:15:7 | message |
|
||||
|
||||
13
ruby/ql/test/library-tests/modules/element_reference.rb
Normal file
13
ruby/ql/test/library-tests/modules/element_reference.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class ClassWithElementRef
|
||||
def [](x)
|
||||
yield x + 1
|
||||
end
|
||||
end
|
||||
|
||||
c = ClassWithElementRef.new
|
||||
|
||||
c[1] { |x| puts x }
|
||||
|
||||
c[1] do |x|
|
||||
puts x
|
||||
end
|
||||
@@ -51,6 +51,7 @@ getMethod
|
||||
| calls.rb:626:1:632:3 | Included | foo | calls.rb:627:5:629:7 | foo |
|
||||
| calls.rb:634:1:639:3 | IncludesIncluded | bar | calls.rb:636:5:638:7 | bar |
|
||||
| calls.rb:649:1:657:3 | CustomNew2 | instance | calls.rb:654:5:656:7 | instance |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef | [] | element_reference.rb:2:5:4:7 | [] |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | hello | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | world | hello.rb:5:5:7:7 | world |
|
||||
| hello.rb:11:1:16:3 | Greeting | message | hello.rb:13:5:15:7 | message |
|
||||
@@ -561,6 +562,10 @@ lookupMethod
|
||||
| calls.rb:649:1:657:3 | CustomNew2 | private_on_main | calls.rb:185:1:186:3 | private_on_main |
|
||||
| calls.rb:649:1:657:3 | CustomNew2 | puts | calls.rb:102:5:102:30 | puts |
|
||||
| calls.rb:649:1:657:3 | CustomNew2 | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef | [] | element_reference.rb:2:5:4:7 | [] |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef | new | calls.rb:117:5:117:16 | new |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef | puts | calls.rb:102:5:102:30 | puts |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| file://:0:0:0:0 | Class | include | calls.rb:108:5:110:7 | include |
|
||||
| file://:0:0:0:0 | Class | module_eval | calls.rb:107:5:107:24 | module_eval |
|
||||
| file://:0:0:0:0 | Class | new | calls.rb:117:5:117:16 | new |
|
||||
@@ -1080,6 +1085,12 @@ enclosingMethod
|
||||
| calls.rb:662:10:662:10 | 2 | calls.rb:661:1:665:3 | capture_parameter |
|
||||
| calls.rb:662:18:664:7 | do ... end | calls.rb:661:1:665:3 | capture_parameter |
|
||||
| calls.rb:663:9:663:9 | x | calls.rb:661:1:665:3 | capture_parameter |
|
||||
| element_reference.rb:2:12:2:12 | x | element_reference.rb:2:5:4:7 | [] |
|
||||
| element_reference.rb:2:12:2:12 | x | element_reference.rb:2:5:4:7 | [] |
|
||||
| element_reference.rb:3:9:3:19 | yield ... | element_reference.rb:2:5:4:7 | [] |
|
||||
| element_reference.rb:3:15:3:15 | x | element_reference.rb:2:5:4:7 | [] |
|
||||
| element_reference.rb:3:15:3:19 | ... + ... | element_reference.rb:2:5:4:7 | [] |
|
||||
| element_reference.rb:3:19:3:19 | 1 | element_reference.rb:2:5:4:7 | [] |
|
||||
| hello.rb:3:9:3:22 | return | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:3:16:3:22 | "hello" | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:3:17:3:21 | hello | hello.rb:2:5:4:7 | hello |
|
||||
|
||||
@@ -36,6 +36,7 @@ getModule
|
||||
| calls.rb:634:1:639:3 | IncludesIncluded |
|
||||
| calls.rb:641:1:645:3 | CustomNew1 |
|
||||
| calls.rb:649:1:657:3 | CustomNew2 |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef |
|
||||
| file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Class |
|
||||
| file://:0:0:0:0 | Complex |
|
||||
@@ -113,6 +114,7 @@ getADeclaration
|
||||
| calls.rb:105:1:113:3 | Module | calls.rb:105:1:113:3 | Module |
|
||||
| calls.rb:115:1:118:3 | Object | calls.rb:1:1:667:52 | calls.rb |
|
||||
| calls.rb:115:1:118:3 | Object | calls.rb:115:1:118:3 | Object |
|
||||
| calls.rb:115:1:118:3 | Object | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| calls.rb:115:1:118:3 | Object | hello.rb:1:1:22:3 | hello.rb |
|
||||
| calls.rb:115:1:118:3 | Object | instance_fields.rb:1:1:29:4 | instance_fields.rb |
|
||||
| calls.rb:115:1:118:3 | Object | modules.rb:1:1:129:4 | modules.rb |
|
||||
@@ -153,6 +155,7 @@ getADeclaration
|
||||
| calls.rb:634:1:639:3 | IncludesIncluded | calls.rb:634:1:639:3 | IncludesIncluded |
|
||||
| calls.rb:641:1:645:3 | CustomNew1 | calls.rb:641:1:645:3 | CustomNew1 |
|
||||
| calls.rb:649:1:657:3 | CustomNew2 | calls.rb:649:1:657:3 | CustomNew2 |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef | element_reference.rb:1:1:5:3 | ClassWithElementRef |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | hello.rb:1:1:8:3 | EnglishWords |
|
||||
| hello.rb:11:1:16:3 | Greeting | hello.rb:11:1:16:3 | Greeting |
|
||||
| hello.rb:18:1:22:3 | HelloWorld | hello.rb:18:1:22:3 | HelloWorld |
|
||||
@@ -238,6 +241,7 @@ getSuperClass
|
||||
| calls.rb:634:1:639:3 | IncludesIncluded | calls.rb:115:1:118:3 | Object |
|
||||
| calls.rb:641:1:645:3 | CustomNew1 | calls.rb:115:1:118:3 | Object |
|
||||
| calls.rb:649:1:657:3 | CustomNew2 | calls.rb:115:1:118:3 | Object |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef | calls.rb:115:1:118:3 | Object |
|
||||
| file://:0:0:0:0 | Class | calls.rb:105:1:113:3 | Module |
|
||||
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Numeric |
|
||||
| file://:0:0:0:0 | FalseClass | calls.rb:115:1:118:3 | Object |
|
||||
@@ -389,6 +393,7 @@ resolveConstantReadAccess
|
||||
| calls.rb:659:1:659:10 | CustomNew2 | CustomNew2 |
|
||||
| calls.rb:662:5:662:11 | Array | Array |
|
||||
| calls.rb:667:20:667:21 | C1 | C1 |
|
||||
| element_reference.rb:7:5:7:23 | ClassWithElementRef | ClassWithElementRef |
|
||||
| hello.rb:12:13:12:24 | EnglishWords | EnglishWords |
|
||||
| hello.rb:18:20:18:27 | Greeting | Greeting |
|
||||
| instance_fields.rb:4:22:4:31 | A_target | A_target |
|
||||
@@ -495,6 +500,7 @@ resolveConstantWriteAccess
|
||||
| calls.rb:634:1:639:3 | IncludesIncluded | IncludesIncluded |
|
||||
| calls.rb:641:1:645:3 | CustomNew1 | CustomNew1 |
|
||||
| calls.rb:649:1:657:3 | CustomNew2 | CustomNew2 |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef | ClassWithElementRef |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | EnglishWords |
|
||||
| hello.rb:11:1:16:3 | Greeting | Greeting |
|
||||
| hello.rb:18:1:22:3 | HelloWorld | HelloWorld |
|
||||
@@ -1611,6 +1617,36 @@ enclosingModule
|
||||
| calls.rb:667:2:667:25 | self | calls.rb:1:1:667:52 | calls.rb |
|
||||
| calls.rb:667:20:667:21 | C1 | calls.rb:1:1:667:52 | calls.rb |
|
||||
| calls.rb:667:20:667:25 | call to new | calls.rb:1:1:667:52 | calls.rb |
|
||||
| element_reference.rb:1:1:5:3 | ClassWithElementRef | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:2:5:4:7 | [] | element_reference.rb:1:1:5:3 | ClassWithElementRef |
|
||||
| element_reference.rb:2:12:2:12 | x | element_reference.rb:1:1:5:3 | ClassWithElementRef |
|
||||
| element_reference.rb:2:12:2:12 | x | element_reference.rb:1:1:5:3 | ClassWithElementRef |
|
||||
| element_reference.rb:3:9:3:19 | yield ... | element_reference.rb:1:1:5:3 | ClassWithElementRef |
|
||||
| element_reference.rb:3:15:3:15 | x | element_reference.rb:1:1:5:3 | ClassWithElementRef |
|
||||
| element_reference.rb:3:15:3:19 | ... + ... | element_reference.rb:1:1:5:3 | ClassWithElementRef |
|
||||
| element_reference.rb:3:19:3:19 | 1 | element_reference.rb:1:1:5:3 | ClassWithElementRef |
|
||||
| element_reference.rb:7:1:7:1 | c | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:7:1:7:27 | ... = ... | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:7:5:7:23 | ClassWithElementRef | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:7:5:7:27 | call to new | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:9:1:9:1 | c | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:9:1:9:19 | ...[...] | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:9:3:9:3 | 1 | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:9:6:9:19 | { ... } | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:9:9:9:9 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:9:9:9:9 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:9:12:9:17 | call to puts | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:9:12:9:17 | self | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:9:17:9:17 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:11:1:11:1 | c | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:11:1:13:3 | ...[...] | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:11:3:11:3 | 1 | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:11:6:13:3 | do ... end | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:11:10:11:10 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:11:10:11:10 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:12:5:12:10 | call to puts | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:12:5:12:10 | self | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| element_reference.rb:12:10:12:10 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | hello.rb:1:1:22:3 | hello.rb |
|
||||
| hello.rb:2:5:4:7 | hello | hello.rb:1:1:8:3 | EnglishWords |
|
||||
| hello.rb:3:9:3:22 | return | hello.rb:1:1:8:3 | EnglishWords |
|
||||
|
||||
@@ -148,6 +148,10 @@ calls.rb:
|
||||
# 649| CustomNew2
|
||||
#-----| -> Object
|
||||
|
||||
element_reference.rb:
|
||||
# 1| ClassWithElementRef
|
||||
#-----| -> Object
|
||||
|
||||
hello.rb:
|
||||
# 1| EnglishWords
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
edges
|
||||
| weak_hashing.rb:3:1:3:8 | password | weak_hashing.rb:6:1:6:1 | x | provenance | |
|
||||
| weak_hashing.rb:3:1:3:8 | password | weak_hashing.rb:10:23:10:30 | password | provenance | |
|
||||
| weak_hashing.rb:3:1:3:8 | password | weak_hashing.rb:11:32:11:39 | password | provenance | |
|
||||
| weak_hashing.rb:4:1:4:8 | username | weak_hashing.rb:12:23:12:30 | username | provenance | |
|
||||
| weak_hashing.rb:6:1:6:1 | x | weak_hashing.rb:13:23:13:23 | x | provenance | |
|
||||
| weak_hashing.rb:30:25:30:38 | password_param | weak_hashing.rb:32:25:32:38 | password_param | provenance | |
|
||||
nodes
|
||||
| weak_hashing.rb:3:1:3:8 | password | semmle.label | password |
|
||||
| weak_hashing.rb:4:1:4:8 | username | semmle.label | username |
|
||||
| weak_hashing.rb:6:1:6:1 | x | semmle.label | x |
|
||||
| weak_hashing.rb:10:23:10:30 | password | semmle.label | password |
|
||||
| weak_hashing.rb:11:32:11:39 | password | semmle.label | password |
|
||||
| weak_hashing.rb:12:23:12:30 | username | semmle.label | username |
|
||||
| weak_hashing.rb:13:23:13:23 | x | semmle.label | x |
|
||||
| weak_hashing.rb:24:23:24:36 | call to get_password | semmle.label | call to get_password |
|
||||
| weak_hashing.rb:28:23:28:42 | ...[...] | semmle.label | ...[...] |
|
||||
| weak_hashing.rb:30:25:30:38 | password_param | semmle.label | password_param |
|
||||
| weak_hashing.rb:32:25:32:38 | password_param | semmle.label | password_param |
|
||||
subpaths
|
||||
#select
|
||||
| weak_hashing.rb:10:23:10:30 | password | weak_hashing.rb:3:1:3:8 | password | weak_hashing.rb:10:23:10:30 | password | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | weak_hashing.rb:3:1:3:8 | password | Sensitive data (password) |
|
||||
| weak_hashing.rb:11:32:11:39 | password | weak_hashing.rb:3:1:3:8 | password | weak_hashing.rb:11:32:11:39 | password | $@ is used in a hashing algorithm (SHA1) that is insecure for password hashing, since it is not a computationally expensive hash function. | weak_hashing.rb:3:1:3:8 | password | Sensitive data (password) |
|
||||
| weak_hashing.rb:12:23:12:30 | username | weak_hashing.rb:4:1:4:8 | username | weak_hashing.rb:12:23:12:30 | username | $@ is used in a hashing algorithm (MD5) that is insecure. | weak_hashing.rb:4:1:4:8 | username | Sensitive data (id) |
|
||||
| weak_hashing.rb:13:23:13:23 | x | weak_hashing.rb:3:1:3:8 | password | weak_hashing.rb:13:23:13:23 | x | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | weak_hashing.rb:3:1:3:8 | password | Sensitive data (password) |
|
||||
| weak_hashing.rb:24:23:24:36 | call to get_password | weak_hashing.rb:24:23:24:36 | call to get_password | weak_hashing.rb:24:23:24:36 | call to get_password | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | weak_hashing.rb:24:23:24:36 | call to get_password | Sensitive data (password) |
|
||||
| weak_hashing.rb:28:23:28:42 | ...[...] | weak_hashing.rb:28:23:28:42 | ...[...] | weak_hashing.rb:28:23:28:42 | ...[...] | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | weak_hashing.rb:28:23:28:42 | ...[...] | Sensitive data (password) |
|
||||
| weak_hashing.rb:32:25:32:38 | password_param | weak_hashing.rb:30:25:30:38 | password_param | weak_hashing.rb:32:25:32:38 | password_param | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | weak_hashing.rb:30:25:30:38 | password_param | Sensitive data (password) |
|
||||
@@ -0,0 +1 @@
|
||||
queries/security/cwe-327/WeakSensitiveDataHashing.ql
|
||||
33
ruby/ql/test/query-tests/security/cwe-327/weak_hashing.rb
Normal file
33
ruby/ql/test/query-tests/security/cwe-327/weak_hashing.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
require 'openssl'
|
||||
|
||||
password = "abcde"
|
||||
username = "some_user"
|
||||
some_data = "foo"
|
||||
x = password
|
||||
|
||||
Digest::MD5.hexdigest(some_data) # OK: input is not sensitive
|
||||
Digest::SHA256.hexdigest(password) # OK: strong hash algorithm
|
||||
Digest::MD5.hexdigest(password) # BAD: weak hash function used for sensitive data
|
||||
OpenSSL::Digest.digest('SHA1', password) # BAD: weak hash function used for sensitive data
|
||||
Digest::MD5.hexdigest(username) # BAD: weak hash function used for sensitive data
|
||||
Digest::MD5.hexdigest(x) # BAD: weak hash function used for sensitive data
|
||||
|
||||
def get_safe_data()
|
||||
return "hello"
|
||||
end
|
||||
|
||||
def get_password()
|
||||
return "changeme"
|
||||
end
|
||||
|
||||
Digest::MD5.hexdigest(get_safe_data()) # OK: input is not sensitive
|
||||
Digest::MD5.hexdigest(get_password()) # BAD: weak hash function used for sensitive data
|
||||
|
||||
some_hash = {password: "changeme", foo: "bar"}
|
||||
Digest::MD5.hexdigest(some_hash[:foo]) # OK: input is not sensitive
|
||||
Digest::MD5.hexdigest(some_hash[:password]) # BAD: weak hash function used for sensitive data
|
||||
|
||||
def a_method(safe_data, password_param)
|
||||
Digest::MD5.hexdigest(safe_data) # OK: input is not sensitive
|
||||
Digest::MD5.hexdigest(password_param) # BAD: weak hash function used for sensitive data
|
||||
end
|
||||
@@ -5,9 +5,9 @@ edges
|
||||
| tst.rb:5:1:5:23 | totally_harmless_string | tst.rb:7:8:7:30 | totally_harmless_string | provenance | |
|
||||
| tst.rb:5:27:5:72 | "707574732822636f646520696e6a6..." | tst.rb:5:1:5:23 | totally_harmless_string | provenance | |
|
||||
| tst.rb:7:8:7:30 | totally_harmless_string | tst.rb:1:7:1:7 | r | provenance | |
|
||||
| tst.rb:7:8:7:30 | totally_harmless_string | tst.rb:7:6:7:31 | call to e | provenance | |
|
||||
| tst.rb:7:8:7:30 | totally_harmless_string | tst.rb:7:6:7:31 | call to e | provenance | Config |
|
||||
| tst.rb:10:11:10:24 | "666f6f626172" | tst.rb:1:7:1:7 | r | provenance | |
|
||||
| tst.rb:10:11:10:24 | "666f6f626172" | tst.rb:10:9:10:25 | call to e | provenance | |
|
||||
| tst.rb:10:11:10:24 | "666f6f626172" | tst.rb:10:9:10:25 | call to e | provenance | Config |
|
||||
| tst.rb:16:1:16:27 | another_questionable_string | tst.rb:17:6:17:32 | another_questionable_string | provenance | |
|
||||
| tst.rb:16:31:16:84 | "\\x70\\x75\\x74\\x73\\x28\\x27\\x68\\..." | tst.rb:16:1:16:27 | another_questionable_string | provenance | |
|
||||
| tst.rb:17:6:17:32 | another_questionable_string | tst.rb:17:6:17:38 | call to strip | provenance | Config |
|
||||
|
||||
Reference in New Issue
Block a user