Skip to content

Commit 10a584f

Browse files
authored
Merge pull request #10517 from hvitved/ruby/regexp-debug
Ruby: Add query for debugging regexp flow
2 parents da272ef + 47411e3 commit 10a584f

File tree

3 files changed

+47
-31
lines changed

3 files changed

+47
-31
lines changed

ruby/ql/lib/codeql/ruby/Regexp.qll

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77

88
import regexp.RegExpTreeView // re-export
99
private import regexp.internal.ParseRegExp
10-
private import codeql.ruby.ast.Literal as AST
10+
private import regexp.internal.RegExpConfiguration
11+
private import codeql.ruby.ast.Literal as Ast
1112
private import codeql.ruby.DataFlow
12-
private import codeql.ruby.controlflow.CfgNodes
1313
private import codeql.ruby.ApiGraphs
14-
private import codeql.ruby.dataflow.internal.tainttrackingforlibraries.TaintTrackingImpl
1514

1615
/**
1716
* Provides utility predicates related to regular expressions.
@@ -47,7 +46,7 @@ abstract class RegExpPatternSource extends DataFlow::Node {
4746
* A regular expression literal, viewed as the pattern source for itself.
4847
*/
4948
private class RegExpLiteralPatternSource extends RegExpPatternSource {
50-
private AST::RegExpLiteral astNode;
49+
private Ast::RegExpLiteral astNode;
5150

5251
RegExpLiteralPatternSource() { astNode = this.asExpr().getExpr() }
5352

@@ -70,7 +69,7 @@ private class StringRegExpPatternSource extends RegExpPatternSource {
7069
override RegExpTerm getRegExpTerm() { result.getRegExp() = this.asExpr().getExpr() }
7170
}
7271

73-
private class RegExpLiteralRegExp extends RegExp, AST::RegExpLiteral {
72+
private class RegExpLiteralRegExp extends RegExp, Ast::RegExpLiteral {
7473
override predicate isDotAll() { this.hasMultilineFlag() }
7574

7675
override predicate isIgnoreCase() { this.hasCaseInsensitiveFlag() }
@@ -115,32 +114,7 @@ class StdLibRegExpInterpretation extends RegExpInterpretation::Range {
115114
mce.getMethodName() = ["match", "match?"] and
116115
this = mce.getArgument(0) and
117116
// exclude https://ruby-doc.org/core-2.4.0/Regexp.html#method-i-match
118-
not mce.getReceiver().asExpr().getExpr() instanceof AST::RegExpLiteral
119-
)
120-
}
121-
}
122-
123-
private class RegExpConfiguration extends Configuration {
124-
RegExpConfiguration() { this = "RegExpConfiguration" }
125-
126-
override predicate isSource(DataFlow::Node source) {
127-
source.asExpr() =
128-
any(ExprCfgNode e |
129-
e.getConstantValue().isString(_) and
130-
not e instanceof ExprNodes::VariableReadAccessCfgNode and
131-
not e instanceof ExprNodes::ConstantReadAccessCfgNode
132-
)
133-
}
134-
135-
override predicate isSink(DataFlow::Node sink) { sink instanceof RegExpInterpretation::Range }
136-
137-
override predicate isSanitizer(DataFlow::Node node) {
138-
// stop flow if `node` is receiver of
139-
// https://ruby-doc.org/core-2.4.0/String.html#method-i-match
140-
exists(DataFlow::CallNode mce |
141-
mce.getMethodName() = ["match", "match?"] and
142-
node = mce.getReceiver() and
143-
mce.getArgument(0).asExpr().getExpr() instanceof AST::RegExpLiteral
117+
not mce.getReceiver().asExpr().getExpr() instanceof Ast::RegExpLiteral
144118
)
145119
}
146120
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @description Used to debug the discovery of regexp literals.
3+
* @kind path-problem
4+
*/
5+
6+
import RegExpConfiguration
7+
import codeql.ruby.dataflow.internal.DataFlowImplForLibraries
8+
import PathGraph
9+
10+
from RegExpConfiguration c, PathNode source, PathNode sink
11+
where c.hasFlowPath(source, sink)
12+
select source.getNode(), source, sink, source.toString()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
private import codeql.ruby.Regexp
2+
private import codeql.ruby.ast.Literal as Ast
3+
private import codeql.ruby.DataFlow
4+
private import codeql.ruby.controlflow.CfgNodes
5+
private import codeql.ruby.dataflow.internal.tainttrackingforlibraries.TaintTrackingImpl
6+
7+
class RegExpConfiguration extends Configuration {
8+
RegExpConfiguration() { this = "RegExpConfiguration" }
9+
10+
override predicate isSource(DataFlow::Node source) {
11+
source.asExpr() =
12+
any(ExprCfgNode e |
13+
e.getConstantValue().isString(_) and
14+
not e instanceof ExprNodes::VariableReadAccessCfgNode and
15+
not e instanceof ExprNodes::ConstantReadAccessCfgNode
16+
)
17+
}
18+
19+
override predicate isSink(DataFlow::Node sink) { sink instanceof RegExpInterpretation::Range }
20+
21+
override predicate isSanitizer(DataFlow::Node node) {
22+
// stop flow if `node` is receiver of
23+
// https://ruby-doc.org/core-2.4.0/String.html#method-i-match
24+
exists(DataFlow::CallNode mce |
25+
mce.getMethodName() = ["match", "match?"] and
26+
node = mce.getReceiver() and
27+
mce.getArgument(0).asExpr().getExpr() instanceof Ast::RegExpLiteral
28+
)
29+
}
30+
}

0 commit comments

Comments
 (0)