Skip to content

Commit 9bd2522

Browse files
authored
Merge pull request github#10760 from hvitved/ruby/regex-taint-flow-restrict
Ruby: Restrict regexp taint flow to `String` summaries
2 parents 56797c5 + 2b75562 commit 9bd2522

File tree

6 files changed

+42
-202
lines changed

6 files changed

+42
-202
lines changed

config/identical-files.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@
7070
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
7171
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
7272
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
73-
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforregexp/TaintTrackingImpl.qll",
7473
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
7574
],
7675
"DataFlow Java/C++/C#/Python Consistency checks": [

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,9 @@ class SummaryNode extends NodeImpl, TSummaryNode {
735735

736736
SummaryNode() { this = TSummaryNode(c, state) }
737737

738+
/** Gets the summarized callable that this node belongs to. */
739+
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() { result = c }
740+
738741
override CfgScope getCfgScope() { none() }
739742

740743
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = c }

ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforregexp/TaintTrackingImpl.qll

Lines changed: 0 additions & 191 deletions
This file was deleted.

ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforregexp/TaintTrackingParameter.qll

Lines changed: 0 additions & 6 deletions
This file was deleted.

ruby/ql/lib/codeql/ruby/frameworks/core/String.qll

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
private import codeql.ruby.AST
44
private import codeql.ruby.ApiGraphs
55
private import codeql.ruby.DataFlow
6-
private import codeql.ruby.dataflow.FlowSummary
6+
private import codeql.ruby.dataflow.FlowSummary as FlowSummary
77
private import codeql.ruby.dataflow.internal.DataFlowDispatch
88
private import codeql.ruby.controlflow.CfgNodes
99
private import codeql.ruby.Regexp as RE
@@ -107,6 +107,18 @@ module String {
107107
preservesValue = false
108108
}
109109

110+
/** A `String` callable with a flow summary. */
111+
abstract class SummarizedCallable extends FlowSummary::SummarizedCallable {
112+
bindingset[this]
113+
SummarizedCallable() { any() }
114+
}
115+
116+
abstract private class SimpleSummarizedCallable extends SummarizedCallable,
117+
FlowSummary::SimpleSummarizedCallable {
118+
bindingset[this]
119+
SimpleSummarizedCallable() { any() }
120+
}
121+
110122
private class NewSummary extends SummarizedCallable {
111123
NewSummary() { this = "String.new" }
112124

ruby/ql/lib/codeql/ruby/regexp/internal/RegExpConfiguration.qll

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
private import codeql.ruby.Regexp
2-
private import codeql.ruby.ast.Literal as Ast
2+
private import codeql.ruby.AST as Ast
3+
private import codeql.ruby.CFG
34
private import codeql.ruby.DataFlow
45
private import codeql.ruby.controlflow.CfgNodes
5-
private import codeql.ruby.dataflow.internal.tainttrackingforregexp.TaintTrackingImpl
6+
private import codeql.ruby.dataflow.internal.DataFlowImplForRegExp
67
private import codeql.ruby.typetracking.TypeTracker
78
private import codeql.ruby.ApiGraphs
9+
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
10+
private import codeql.ruby.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
11+
private import codeql.ruby.dataflow.FlowSummary as FlowSummary
12+
private import codeql.ruby.frameworks.core.String
813

914
class RegExpConfiguration extends Configuration {
1015
RegExpConfiguration() { this = "RegExpConfiguration" }
@@ -20,7 +25,7 @@ class RegExpConfiguration extends Configuration {
2025

2126
override predicate isSink(DataFlow::Node sink) { sink instanceof RegExpInterpretation::Range }
2227

23-
override predicate isSanitizer(DataFlow::Node node) {
28+
override predicate isBarrier(DataFlow::Node node) {
2429
exists(DataFlow::CallNode mce | mce.getMethodName() = ["match", "match?"] |
2530
// receiver of https://ruby-doc.org/core-2.4.0/String.html#method-i-match
2631
node = mce.getReceiver() and
@@ -31,6 +36,24 @@ class RegExpConfiguration extends Configuration {
3136
mce.getReceiver() = trackRegexpType()
3237
)
3338
}
39+
40+
override predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
41+
// include taint flow through `String` summaries,
42+
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false) and
43+
nodeFrom.(DataFlowPrivate::SummaryNode).getSummarizedCallable() instanceof
44+
String::SummarizedCallable
45+
or
46+
// string concatenations, and
47+
exists(CfgNodes::ExprNodes::OperationCfgNode op |
48+
op = nodeTo.asExpr() and
49+
op.getAnOperand() = nodeFrom.asExpr() and
50+
op.getExpr().(Ast::BinaryOperation).getOperator() = "+"
51+
)
52+
or
53+
// string interpolations
54+
nodeFrom.asExpr() =
55+
nodeTo.asExpr().(CfgNodes::ExprNodes::StringlikeLiteralCfgNode).getAComponent()
56+
}
3457
}
3558

3659
private DataFlow::LocalSourceNode trackRegexpType(TypeTracker t) {

0 commit comments

Comments
 (0)