Skip to content

Commit ce49592

Browse files
committed
Ruby: Flow through hash-splat expressions
1 parent a7b39eb commit ce49592

File tree

4 files changed

+31
-2
lines changed

4 files changed

+31
-2
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ private class Argument extends CfgNodes::ExprCfgNode {
179179
this = call.getArgument(i) and
180180
not this.getExpr() instanceof BlockArgument and
181181
not this.getExpr().(Pair).getKey().getConstantValue().isSymbol(_) and
182+
not this.getExpr() instanceof HashSplatExpr and
182183
arg.isPositional(i)
183184
)
184185
or
@@ -189,6 +190,10 @@ private class Argument extends CfgNodes::ExprCfgNode {
189190
)
190191
or
191192
this = call.getReceiver() and arg.isSelf()
193+
or
194+
this = call.getAnArgument() and
195+
this.getExpr() instanceof HashSplatExpr and
196+
arg.isHashSplat()
192197
}
193198

194199
/** Holds if this expression is the `i`th argument of `c`. */

ruby/ql/lib/codeql/ruby/frameworks/Core.qll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,15 @@ private class SplatSummary extends SummarizedCallable {
7373
preservesValue = true
7474
}
7575
}
76+
77+
private class HashSplatSummary extends SummarizedCallable {
78+
HashSplatSummary() { this = "**(hash-splat)" }
79+
80+
override HashSplatExpr getACall() { any() }
81+
82+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
83+
input = "Argument[self].WithElement[any]" and
84+
output = "ReturnValue" and
85+
preservesValue = true
86+
}
87+
}

ruby/ql/test/library-tests/dataflow/params/params-flow.expected

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ edges
2222
| params_flow.rb:33:12:33:19 | call to taint : | params_flow.rb:25:12:25:13 | p1 : |
2323
| params_flow.rb:33:26:33:34 | call to taint : | params_flow.rb:25:17:25:24 | **kwargs [element :p2] : |
2424
| params_flow.rb:33:41:33:49 | call to taint : | params_flow.rb:25:17:25:24 | **kwargs [element :p3] : |
25+
| params_flow.rb:34:14:34:22 | call to taint : | params_flow.rb:35:25:35:28 | args [element :p3] : |
26+
| params_flow.rb:35:12:35:20 | call to taint : | params_flow.rb:25:12:25:13 | p1 : |
27+
| params_flow.rb:35:23:35:28 | ** ... [element :p3] : | params_flow.rb:25:17:25:24 | **kwargs [element :p3] : |
28+
| params_flow.rb:35:25:35:28 | args [element :p3] : | params_flow.rb:35:23:35:28 | ** ... [element :p3] : |
2529
nodes
2630
| params_flow.rb:9:16:9:17 | p1 : | semmle.label | p1 : |
2731
| params_flow.rb:9:20:9:21 | p2 : | semmle.label | p2 : |
@@ -52,6 +56,10 @@ nodes
5256
| params_flow.rb:33:12:33:19 | call to taint : | semmle.label | call to taint : |
5357
| params_flow.rb:33:26:33:34 | call to taint : | semmle.label | call to taint : |
5458
| params_flow.rb:33:41:33:49 | call to taint : | semmle.label | call to taint : |
59+
| params_flow.rb:34:14:34:22 | call to taint : | semmle.label | call to taint : |
60+
| params_flow.rb:35:12:35:20 | call to taint : | semmle.label | call to taint : |
61+
| params_flow.rb:35:23:35:28 | ** ... [element :p3] : | semmle.label | ** ... [element :p3] : |
62+
| params_flow.rb:35:25:35:28 | args [element :p3] : | semmle.label | args [element :p3] : |
5563
subpaths
5664
#select
5765
| params_flow.rb:10:10:10:11 | p1 | params_flow.rb:14:12:14:19 | call to taint : | params_flow.rb:10:10:10:11 | p1 | $@ | params_flow.rb:14:12:14:19 | call to taint : | call to taint : |
@@ -63,5 +71,7 @@ subpaths
6371
| params_flow.rb:18:10:18:11 | p2 | params_flow.rb:22:13:22:20 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:22:13:22:20 | call to taint : | call to taint : |
6472
| params_flow.rb:18:10:18:11 | p2 | params_flow.rb:23:16:23:23 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:23:16:23:23 | call to taint : | call to taint : |
6573
| params_flow.rb:26:10:26:11 | p1 | params_flow.rb:33:12:33:19 | call to taint : | params_flow.rb:26:10:26:11 | p1 | $@ | params_flow.rb:33:12:33:19 | call to taint : | call to taint : |
74+
| params_flow.rb:26:10:26:11 | p1 | params_flow.rb:35:12:35:20 | call to taint : | params_flow.rb:26:10:26:11 | p1 | $@ | params_flow.rb:35:12:35:20 | call to taint : | call to taint : |
6675
| params_flow.rb:28:10:28:22 | ( ... ) | params_flow.rb:33:26:33:34 | call to taint : | params_flow.rb:28:10:28:22 | ( ... ) | $@ | params_flow.rb:33:26:33:34 | call to taint : | call to taint : |
6776
| params_flow.rb:29:10:29:22 | ( ... ) | params_flow.rb:33:41:33:49 | call to taint : | params_flow.rb:29:10:29:22 | ( ... ) | $@ | params_flow.rb:33:41:33:49 | call to taint : | call to taint : |
77+
| params_flow.rb:29:10:29:22 | ( ... ) | params_flow.rb:34:14:34:22 | call to taint : | params_flow.rb:29:10:29:22 | ( ... ) | $@ | params_flow.rb:34:14:34:22 | call to taint : | call to taint : |

ruby/ql/test/library-tests/dataflow/params/params_flow.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ def keyword(p1:, p2:)
2323
keyword(:p2 => taint(7), :p1 => taint(8))
2424

2525
def kwargs(p1:, **kwargs)
26-
sink p1 # $ hasValueFlow=9
26+
sink p1 # $ hasValueFlow=9 $ hasValueFlow=13
2727
sink (kwargs[:p1])
2828
sink (kwargs[:p2]) # $ hasValueFlow=10
29-
sink (kwargs[:p3]) # $ hasValueFlow=11
29+
sink (kwargs[:p3]) # $ hasValueFlow=11 $ hasValueFlow=12
3030
sink (kwargs[:p4])
3131
end
3232

3333
kwargs(p1: taint(9), p2: taint(10), p3: taint(11), p4: "")
34+
args = { p3: taint(12), p4: "" }
35+
kwargs(p1: taint(13), **args)

0 commit comments

Comments
 (0)