Ruby: Add CallNode.getKeywordArgumentIncludeHashArgument

This commit is contained in:
Rasmus Wriedt Larsen
2022-08-19 15:54:15 +02:00
parent 10968bf115
commit 9eda630965
7 changed files with 46 additions and 93 deletions

View File

@@ -87,6 +87,46 @@ class CallNode extends LocalSourceNode, ExprNode {
/** Gets the block of this call. */
Node getBlock() { result.asExpr() = node.getBlock() }
/**
* Gets the data-flow node corresponding to the named argument of the call
* corresponding to this data-flow node, also including values passed with (pre Ruby
* 2.0) hash arguments.
*
* Such hash arguments are tracked back to their source location within functions, but
* no inter-procedural analysis occurs.
*
* This means all 3 variants below will be handled by this predicate:
*
* ```ruby
* foo(..., some_option: 42)
* foo(..., { some_option: 42 })
* options = { some_option: 42 }
* foo(..., options)
* ```
*/
Node getKeywordArgumentIncludeHashArgument(string name) {
// to reduce number of computed tuples, I have put bindingset on both this and name,
// meaning we only do the local backwards tracking for known calls and known names.
// (not because a performance problem was seen, it just seemed right).
result = this.getKeywordArgument(name)
or
exists(CfgNodes::ExprNodes::PairCfgNode pair |
pair =
this.getArgument(_)
.getALocalSource()
.asExpr()
.(CfgNodes::ExprNodes::HashLiteralCfgNode)
.getAKeyValuePair() and
exprNode(pair.getKey())
.getALocalSource()
.asExpr()
.getExpr()
.getConstantValue()
.isStringlikeValue(name) and
result.asExpr() = pair.getValue()
)
}
}
/**

View File

@@ -66,24 +66,7 @@ class ExconHttpRequest extends HTTP::Client::Request::Range, DataFlow::CallNode
DataFlow::Node getCertificateValidationControllingValue() {
exists(DataFlow::CallNode newCall | newCall = connectionNode.getAValueReachableFromSource() |
// Check for `ssl_verify_peer: false`
result = newCall.getKeywordArgument("ssl_verify_peer")
or
// using a hashliteral
exists(
DataFlow::LocalSourceNode optionsNode, CfgNodes::ExprNodes::PairCfgNode p,
DataFlow::Node key
|
// can't flow to argument 0, since that's the URL
optionsNode.flowsTo(newCall.getArgument(any(int i | i > 0))) and
p = optionsNode.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair() and
key.asExpr() = p.getKey() and
key.getALocalSource()
.asExpr()
.getExpr()
.getConstantValue()
.isStringlikeValue("ssl_verify_peer") and
result.asExpr() = p.getValue()
)
result = newCall.getKeywordArgumentIncludeHashArgument("ssl_verify_peer")
)
}

View File

@@ -60,20 +60,7 @@ class FaradayHttpRequest extends HTTP::Client::Request::Range, DataFlow::CallNod
argName in ["verify", "verify_mode"] and
exists(DataFlow::Node sslValue, DataFlow::CallNode newCall |
newCall = connectionNode.getAValueReachableFromSource() and
sslValue = newCall.getKeywordArgument("ssl")
or
// using a hashliteral
exists(
DataFlow::LocalSourceNode optionsNode, CfgNodes::ExprNodes::PairCfgNode p,
DataFlow::Node key
|
// can't flow to argument 0, since that's the URL
optionsNode.flowsTo(newCall.getArgument(any(int i | i > 0))) and
p = optionsNode.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair() and
key.asExpr() = p.getKey() and
key.getALocalSource().asExpr().getExpr().getConstantValue().isStringlikeValue("ssl") and
sslValue.asExpr() = p.getValue()
)
sslValue = newCall.getKeywordArgumentIncludeHashArgument("ssl")
|
exists(CfgNodes::ExprNodes::PairCfgNode p, DataFlow::Node key |
p = sslValue.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair() and

View File

@@ -50,23 +50,7 @@ class HttpartyRequest extends HTTP::Client::Request::Range, DataFlow::CallNode {
/** Gets the value that controls certificate validation, if any. */
DataFlow::Node getCertificateValidationControllingValue() {
result = this.getKeywordArgument(["verify", "verify_peer"])
or
// using a hashliteral
exists(
DataFlow::LocalSourceNode optionsNode, CfgNodes::ExprNodes::PairCfgNode p, DataFlow::Node key
|
// can't flow to argument 0, since that's the URL
optionsNode.flowsTo(this.getArgument(any(int i | i > 0))) and
p = optionsNode.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair() and
key.asExpr() = p.getKey() and
key.getALocalSource()
.asExpr()
.getExpr()
.getConstantValue()
.isStringlikeValue(["verify", "verify_peer"]) and
result.asExpr() = p.getValue()
)
result = this.getKeywordArgumentIncludeHashArgument(["verify", "verify_peer"])
}
override predicate disablesCertificateValidation(

View File

@@ -39,22 +39,7 @@ class OpenUriRequest extends HTTP::Client::Request::Range, DataFlow::CallNode {
/** Gets the value that controls certificate validation, if any. */
DataFlow::Node getCertificateValidationControllingValue() {
result = this.getKeywordArgument("ssl_verify_mode")
or
// using a hashliteral
exists(
DataFlow::LocalSourceNode optionsNode, CfgNodes::ExprNodes::PairCfgNode p, DataFlow::Node key
|
optionsNode.flowsTo(this.getArgument(_)) and
p = optionsNode.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair() and
key.asExpr() = p.getKey() and
key.getALocalSource()
.asExpr()
.getExpr()
.getConstantValue()
.isStringlikeValue("ssl_verify_mode") and
result.asExpr() = p.getValue()
)
result = this.getKeywordArgumentIncludeHashArgument("ssl_verify_mode")
}
override predicate disablesCertificateValidation(

View File

@@ -50,20 +50,7 @@ class RestClientHttpRequest extends HTTP::Client::Request::Range, DataFlow::Call
/** Gets the value that controls certificate validation, if any. */
DataFlow::Node getCertificateValidationControllingValue() {
exists(DataFlow::CallNode newCall | newCall = connectionNode.getAValueReachableFromSource() |
result = newCall.getKeywordArgument("verify_ssl")
or
// using a hashliteral
exists(
DataFlow::LocalSourceNode optionsNode, CfgNodes::ExprNodes::PairCfgNode p,
DataFlow::Node key
|
// can't flow to argument 0, since that's the URL
optionsNode.flowsTo(newCall.getArgument(any(int i | i > 0))) and
p = optionsNode.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair() and
key.asExpr() = p.getKey() and
key.getALocalSource().asExpr().getExpr().getConstantValue().isStringlikeValue("verify_ssl") and
result.asExpr() = p.getValue()
)
result = newCall.getKeywordArgumentIncludeHashArgument("verify_ssl")
)
}

View File

@@ -31,20 +31,7 @@ class TyphoeusHttpRequest extends HTTP::Client::Request::Range, DataFlow::CallNo
/** Gets the value that controls certificate validation, if any. */
DataFlow::Node getCertificateValidationControllingValue() {
result = this.getKeywordArgument("ssl_verifypeer")
or
// using a hashliteral
exists(
DataFlow::LocalSourceNode optionsNode, CfgNodes::ExprNodes::PairCfgNode p,
DataFlow::Node key
|
// can't flow to argument 0, since that's the URL
optionsNode.flowsTo(this.getArgument(any(int i | i > 0))) and
p = optionsNode.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair() and
key.asExpr() = p.getKey() and
key.getALocalSource().asExpr().getExpr().getConstantValue().isStringlikeValue("ssl_verifypeer") and
result.asExpr() = p.getValue()
)
result = this.getKeywordArgumentIncludeHashArgument("ssl_verifypeer")
}
override predicate disablesCertificateValidation(