Merge pull request #10517 from hvitved/ruby/regexp-debug

Ruby: Add query for debugging regexp flow
This commit is contained in:
Tom Hvitved
2022-09-22 11:50:50 +02:00
committed by GitHub
3 changed files with 47 additions and 31 deletions

View File

@@ -7,11 +7,10 @@
import regexp.RegExpTreeView // re-export
private import regexp.internal.ParseRegExp
private import codeql.ruby.ast.Literal as AST
private import regexp.internal.RegExpConfiguration
private import codeql.ruby.ast.Literal as Ast
private import codeql.ruby.DataFlow
private import codeql.ruby.controlflow.CfgNodes
private import codeql.ruby.ApiGraphs
private import codeql.ruby.dataflow.internal.tainttrackingforlibraries.TaintTrackingImpl
/**
* Provides utility predicates related to regular expressions.
@@ -47,7 +46,7 @@ abstract class RegExpPatternSource extends DataFlow::Node {
* A regular expression literal, viewed as the pattern source for itself.
*/
private class RegExpLiteralPatternSource extends RegExpPatternSource {
private AST::RegExpLiteral astNode;
private Ast::RegExpLiteral astNode;
RegExpLiteralPatternSource() { astNode = this.asExpr().getExpr() }
@@ -70,7 +69,7 @@ private class StringRegExpPatternSource extends RegExpPatternSource {
override RegExpTerm getRegExpTerm() { result.getRegExp() = this.asExpr().getExpr() }
}
private class RegExpLiteralRegExp extends RegExp, AST::RegExpLiteral {
private class RegExpLiteralRegExp extends RegExp, Ast::RegExpLiteral {
override predicate isDotAll() { this.hasMultilineFlag() }
override predicate isIgnoreCase() { this.hasCaseInsensitiveFlag() }
@@ -115,32 +114,7 @@ class StdLibRegExpInterpretation extends RegExpInterpretation::Range {
mce.getMethodName() = ["match", "match?"] and
this = mce.getArgument(0) and
// exclude https://ruby-doc.org/core-2.4.0/Regexp.html#method-i-match
not mce.getReceiver().asExpr().getExpr() instanceof AST::RegExpLiteral
)
}
}
private class RegExpConfiguration extends Configuration {
RegExpConfiguration() { this = "RegExpConfiguration" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() =
any(ExprCfgNode e |
e.getConstantValue().isString(_) and
not e instanceof ExprNodes::VariableReadAccessCfgNode and
not e instanceof ExprNodes::ConstantReadAccessCfgNode
)
}
override predicate isSink(DataFlow::Node sink) { sink instanceof RegExpInterpretation::Range }
override predicate isSanitizer(DataFlow::Node node) {
// stop flow if `node` is receiver of
// https://ruby-doc.org/core-2.4.0/String.html#method-i-match
exists(DataFlow::CallNode mce |
mce.getMethodName() = ["match", "match?"] and
node = mce.getReceiver() and
mce.getArgument(0).asExpr().getExpr() instanceof AST::RegExpLiteral
not mce.getReceiver().asExpr().getExpr() instanceof Ast::RegExpLiteral
)
}
}

View File

@@ -0,0 +1,12 @@
/**
* @description Used to debug the discovery of regexp literals.
* @kind path-problem
*/
import RegExpConfiguration
import codeql.ruby.dataflow.internal.DataFlowImplForLibraries
import PathGraph
from RegExpConfiguration c, PathNode source, PathNode sink
where c.hasFlowPath(source, sink)
select source.getNode(), source, sink, source.toString()

View File

@@ -0,0 +1,30 @@
private import codeql.ruby.Regexp
private import codeql.ruby.ast.Literal as Ast
private import codeql.ruby.DataFlow
private import codeql.ruby.controlflow.CfgNodes
private import codeql.ruby.dataflow.internal.tainttrackingforlibraries.TaintTrackingImpl
class RegExpConfiguration extends Configuration {
RegExpConfiguration() { this = "RegExpConfiguration" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() =
any(ExprCfgNode e |
e.getConstantValue().isString(_) and
not e instanceof ExprNodes::VariableReadAccessCfgNode and
not e instanceof ExprNodes::ConstantReadAccessCfgNode
)
}
override predicate isSink(DataFlow::Node sink) { sink instanceof RegExpInterpretation::Range }
override predicate isSanitizer(DataFlow::Node node) {
// stop flow if `node` is receiver of
// https://ruby-doc.org/core-2.4.0/String.html#method-i-match
exists(DataFlow::CallNode mce |
mce.getMethodName() = ["match", "match?"] and
node = mce.getReceiver() and
mce.getArgument(0).asExpr().getExpr() instanceof Ast::RegExpLiteral
)
}
}