Skip to content

Commit 0160c37

Browse files
committed
Ruby: add flow summaries for Object#dup and Kernel#tap
1 parent 5d55daa commit 0160c37

File tree

6 files changed

+180
-0
lines changed

6 files changed

+180
-0
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,14 @@ module Kernel {
167167

168168
override DataFlow::Node getCode() { result = this.getArgument(0) }
169169
}
170+
171+
private class TapSummary extends SimpleSummarizedCallable {
172+
TapSummary() { this = "tap" }
173+
174+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
175+
input = "Argument[self]" and
176+
output = ["ReturnValue", "Argument[block].Parameter[0]"] and
177+
preservesValue = true
178+
}
179+
}
170180
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44

55
private import codeql.ruby.AST
6+
private import codeql.ruby.dataflow.FlowSummary
67

78
/**
89
* Provides modeling for the `Object` class.
@@ -31,4 +32,14 @@ module Object {
3132
"taint", "tainted?", "to_enum", "to_s", "trust", "untaint", "untrust", "untrusted?"
3233
]
3334
}
35+
36+
private class DupSummary extends SimpleSummarizedCallable {
37+
DupSummary() { this = "dup" }
38+
39+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
40+
input = "Argument[self]" and
41+
output = "ReturnValue" and
42+
preservesValue = true
43+
}
44+
}
3445
}

ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,39 @@
243243
| local_dataflow.rb:107:9:107:17 | [post] self | local_dataflow.rb:108:3:108:9 | self |
244244
| local_dataflow.rb:107:9:107:17 | call to source | local_dataflow.rb:107:5:107:7 | ... && ... |
245245
| local_dataflow.rb:107:9:107:17 | self | local_dataflow.rb:108:3:108:9 | self |
246+
| local_dataflow.rb:111:1:114:3 | self (object_dup) | local_dataflow.rb:112:3:112:21 | self |
247+
| local_dataflow.rb:111:1:114:3 | self in object_dup | local_dataflow.rb:111:1:114:3 | self (object_dup) |
248+
| local_dataflow.rb:112:3:112:21 | [post] self | local_dataflow.rb:112:8:112:16 | self |
249+
| local_dataflow.rb:112:3:112:21 | self | local_dataflow.rb:112:8:112:16 | self |
250+
| local_dataflow.rb:112:8:112:16 | [post] self | local_dataflow.rb:113:3:113:25 | self |
251+
| local_dataflow.rb:112:8:112:16 | call to source | local_dataflow.rb:112:8:112:20 | call to dup |
252+
| local_dataflow.rb:112:8:112:16 | self | local_dataflow.rb:113:3:113:25 | self |
253+
| local_dataflow.rb:113:3:113:25 | [post] self | local_dataflow.rb:113:8:113:16 | self |
254+
| local_dataflow.rb:113:3:113:25 | self | local_dataflow.rb:113:8:113:16 | self |
255+
| local_dataflow.rb:113:8:113:16 | call to source | local_dataflow.rb:113:8:113:20 | call to dup |
256+
| local_dataflow.rb:113:8:113:20 | call to dup | local_dataflow.rb:113:8:113:24 | call to dup |
257+
| local_dataflow.rb:116:1:120:3 | self (kernel_tap) | local_dataflow.rb:117:3:117:24 | self |
258+
| local_dataflow.rb:116:1:120:3 | self in kernel_tap | local_dataflow.rb:116:1:120:3 | self (kernel_tap) |
259+
| local_dataflow.rb:117:3:117:24 | [post] self | local_dataflow.rb:117:8:117:16 | self |
260+
| local_dataflow.rb:117:3:117:24 | self | local_dataflow.rb:117:8:117:16 | self |
261+
| local_dataflow.rb:117:8:117:16 | [post] self | local_dataflow.rb:118:3:118:11 | self |
262+
| local_dataflow.rb:117:8:117:16 | call to source | local_dataflow.rb:117:8:117:23 | call to tap |
263+
| local_dataflow.rb:117:8:117:16 | self | local_dataflow.rb:118:3:118:11 | self |
264+
| local_dataflow.rb:118:3:118:11 | [post] self | local_dataflow.rb:119:3:119:31 | self |
265+
| local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap |
266+
| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:119:3:119:31 | self |
267+
| local_dataflow.rb:118:17:118:31 | <captured> | local_dataflow.rb:118:23:118:29 | self |
268+
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:20:118:20 | x |
269+
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:28:118:28 | x |
270+
| local_dataflow.rb:119:3:119:31 | [post] self | local_dataflow.rb:119:8:119:16 | self |
271+
| local_dataflow.rb:119:3:119:31 | self | local_dataflow.rb:119:8:119:16 | self |
272+
| local_dataflow.rb:119:8:119:16 | call to source | local_dataflow.rb:119:8:119:23 | call to tap |
273+
| local_dataflow.rb:119:8:119:23 | call to tap | local_dataflow.rb:119:8:119:30 | call to tap |
274+
| local_dataflow.rb:122:1:124:3 | self (dup_tap) | local_dataflow.rb:123:3:123:50 | self |
275+
| local_dataflow.rb:122:1:124:3 | self in dup_tap | local_dataflow.rb:122:1:124:3 | self (dup_tap) |
276+
| local_dataflow.rb:123:3:123:50 | [post] self | local_dataflow.rb:123:8:123:16 | self |
277+
| local_dataflow.rb:123:3:123:50 | self | local_dataflow.rb:123:8:123:16 | self |
278+
| local_dataflow.rb:123:8:123:16 | call to source | local_dataflow.rb:123:8:123:20 | call to dup |
279+
| local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap |
280+
| local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup |
281+
| local_dataflow.rb:123:26:123:45 | <captured> | local_dataflow.rb:123:32:123:43 | self |

ruby/ql/test/library-tests/dataflow/local/Nodes.expected

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ ret
1414
| local_dataflow.rb:52:3:52:10 | "normal" |
1515
| local_dataflow.rb:89:3:89:9 | call to sink |
1616
| local_dataflow.rb:108:3:108:9 | call to sink |
17+
| local_dataflow.rb:113:3:113:25 | call to sink |
18+
| local_dataflow.rb:118:23:118:29 | call to sink |
19+
| local_dataflow.rb:119:3:119:31 | call to sink |
20+
| local_dataflow.rb:123:3:123:50 | call to sink |
21+
| local_dataflow.rb:123:32:123:43 | call to puts |
1722
arg
1823
| local_dataflow.rb:3:8:3:10 | self | local_dataflow.rb:3:8:3:10 | call to p | self |
1924
| local_dataflow.rb:3:10:3:10 | a | local_dataflow.rb:3:8:3:10 | call to p | position 0 |
@@ -124,3 +129,44 @@ arg
124129
| local_dataflow.rb:107:16:107:16 | 8 | local_dataflow.rb:107:9:107:17 | call to source | position 0 |
125130
| local_dataflow.rb:108:3:108:9 | self | local_dataflow.rb:108:3:108:9 | call to sink | self |
126131
| local_dataflow.rb:108:8:108:8 | b | local_dataflow.rb:108:3:108:9 | call to sink | position 0 |
132+
| local_dataflow.rb:112:3:112:21 | self | local_dataflow.rb:112:3:112:21 | call to sink | self |
133+
| local_dataflow.rb:112:8:112:16 | call to source | local_dataflow.rb:112:8:112:20 | call to dup | self |
134+
| local_dataflow.rb:112:8:112:16 | self | local_dataflow.rb:112:8:112:16 | call to source | self |
135+
| local_dataflow.rb:112:8:112:20 | call to dup | local_dataflow.rb:112:3:112:21 | call to sink | position 0 |
136+
| local_dataflow.rb:112:15:112:15 | 1 | local_dataflow.rb:112:8:112:16 | call to source | position 0 |
137+
| local_dataflow.rb:113:3:113:25 | self | local_dataflow.rb:113:3:113:25 | call to sink | self |
138+
| local_dataflow.rb:113:8:113:16 | call to source | local_dataflow.rb:113:8:113:20 | call to dup | self |
139+
| local_dataflow.rb:113:8:113:16 | self | local_dataflow.rb:113:8:113:16 | call to source | self |
140+
| local_dataflow.rb:113:8:113:20 | call to dup | local_dataflow.rb:113:8:113:24 | call to dup | self |
141+
| local_dataflow.rb:113:8:113:24 | call to dup | local_dataflow.rb:113:3:113:25 | call to sink | position 0 |
142+
| local_dataflow.rb:113:15:113:15 | 1 | local_dataflow.rb:113:8:113:16 | call to source | position 0 |
143+
| local_dataflow.rb:117:3:117:24 | self | local_dataflow.rb:117:3:117:24 | call to sink | self |
144+
| local_dataflow.rb:117:8:117:16 | call to source | local_dataflow.rb:117:8:117:23 | call to tap | self |
145+
| local_dataflow.rb:117:8:117:16 | self | local_dataflow.rb:117:8:117:16 | call to source | self |
146+
| local_dataflow.rb:117:8:117:23 | call to tap | local_dataflow.rb:117:3:117:24 | call to sink | position 0 |
147+
| local_dataflow.rb:117:15:117:15 | 1 | local_dataflow.rb:117:8:117:16 | call to source | position 0 |
148+
| local_dataflow.rb:117:22:117:23 | { ... } | local_dataflow.rb:117:8:117:23 | call to tap | block |
149+
| local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap | self |
150+
| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:118:3:118:11 | call to source | self |
151+
| local_dataflow.rb:118:10:118:10 | 1 | local_dataflow.rb:118:3:118:11 | call to source | position 0 |
152+
| local_dataflow.rb:118:17:118:31 | { ... } | local_dataflow.rb:118:3:118:31 | call to tap | block |
153+
| local_dataflow.rb:118:23:118:29 | self | local_dataflow.rb:118:23:118:29 | call to sink | self |
154+
| local_dataflow.rb:118:28:118:28 | x | local_dataflow.rb:118:23:118:29 | call to sink | position 0 |
155+
| local_dataflow.rb:119:3:119:31 | self | local_dataflow.rb:119:3:119:31 | call to sink | self |
156+
| local_dataflow.rb:119:8:119:16 | call to source | local_dataflow.rb:119:8:119:23 | call to tap | self |
157+
| local_dataflow.rb:119:8:119:16 | self | local_dataflow.rb:119:8:119:16 | call to source | self |
158+
| local_dataflow.rb:119:8:119:23 | call to tap | local_dataflow.rb:119:8:119:30 | call to tap | self |
159+
| local_dataflow.rb:119:8:119:30 | call to tap | local_dataflow.rb:119:3:119:31 | call to sink | position 0 |
160+
| local_dataflow.rb:119:15:119:15 | 1 | local_dataflow.rb:119:8:119:16 | call to source | position 0 |
161+
| local_dataflow.rb:119:22:119:23 | { ... } | local_dataflow.rb:119:8:119:23 | call to tap | block |
162+
| local_dataflow.rb:119:29:119:30 | { ... } | local_dataflow.rb:119:8:119:30 | call to tap | block |
163+
| local_dataflow.rb:123:3:123:50 | self | local_dataflow.rb:123:3:123:50 | call to sink | self |
164+
| local_dataflow.rb:123:8:123:16 | call to source | local_dataflow.rb:123:8:123:20 | call to dup | self |
165+
| local_dataflow.rb:123:8:123:16 | self | local_dataflow.rb:123:8:123:16 | call to source | self |
166+
| local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap | self |
167+
| local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup | self |
168+
| local_dataflow.rb:123:8:123:49 | call to dup | local_dataflow.rb:123:3:123:50 | call to sink | position 0 |
169+
| local_dataflow.rb:123:15:123:15 | 1 | local_dataflow.rb:123:8:123:16 | call to source | position 0 |
170+
| local_dataflow.rb:123:26:123:45 | { ... } | local_dataflow.rb:123:8:123:45 | call to tap | block |
171+
| local_dataflow.rb:123:32:123:43 | self | local_dataflow.rb:123:32:123:43 | call to puts | self |
172+
| local_dataflow.rb:123:37:123:43 | "hello" | local_dataflow.rb:123:32:123:43 | call to puts | position 0 |

ruby/ql/test/library-tests/dataflow/local/TaintflowStep.expected

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,28 @@ edges
3333
| local_dataflow.rb:106:7:106:15 | call to source : | local_dataflow.rb:108:8:108:8 | b |
3434
| local_dataflow.rb:107:9:107:17 | call to source : | local_dataflow.rb:108:8:108:8 | b |
3535
| local_dataflow.rb:107:9:107:17 | call to source : | local_dataflow.rb:108:8:108:8 | b |
36+
| local_dataflow.rb:112:8:112:16 | call to source : | local_dataflow.rb:112:8:112:20 | call to dup |
37+
| local_dataflow.rb:112:8:112:16 | call to source : | local_dataflow.rb:112:8:112:20 | call to dup |
38+
| local_dataflow.rb:113:8:113:16 | call to source : | local_dataflow.rb:113:8:113:20 | call to dup : |
39+
| local_dataflow.rb:113:8:113:16 | call to source : | local_dataflow.rb:113:8:113:20 | call to dup : |
40+
| local_dataflow.rb:113:8:113:20 | call to dup : | local_dataflow.rb:113:8:113:24 | call to dup |
41+
| local_dataflow.rb:113:8:113:20 | call to dup : | local_dataflow.rb:113:8:113:24 | call to dup |
42+
| local_dataflow.rb:117:8:117:16 | call to source : | local_dataflow.rb:117:8:117:23 | call to tap |
43+
| local_dataflow.rb:117:8:117:16 | call to source : | local_dataflow.rb:117:8:117:23 | call to tap |
44+
| local_dataflow.rb:118:3:118:11 | call to source : | local_dataflow.rb:118:20:118:20 | x : |
45+
| local_dataflow.rb:118:3:118:11 | call to source : | local_dataflow.rb:118:20:118:20 | x : |
46+
| local_dataflow.rb:118:20:118:20 | x : | local_dataflow.rb:118:28:118:28 | x |
47+
| local_dataflow.rb:118:20:118:20 | x : | local_dataflow.rb:118:28:118:28 | x |
48+
| local_dataflow.rb:119:8:119:16 | call to source : | local_dataflow.rb:119:8:119:23 | call to tap : |
49+
| local_dataflow.rb:119:8:119:16 | call to source : | local_dataflow.rb:119:8:119:23 | call to tap : |
50+
| local_dataflow.rb:119:8:119:23 | call to tap : | local_dataflow.rb:119:8:119:30 | call to tap |
51+
| local_dataflow.rb:119:8:119:23 | call to tap : | local_dataflow.rb:119:8:119:30 | call to tap |
52+
| local_dataflow.rb:123:8:123:16 | call to source : | local_dataflow.rb:123:8:123:20 | call to dup : |
53+
| local_dataflow.rb:123:8:123:16 | call to source : | local_dataflow.rb:123:8:123:20 | call to dup : |
54+
| local_dataflow.rb:123:8:123:20 | call to dup : | local_dataflow.rb:123:8:123:45 | call to tap : |
55+
| local_dataflow.rb:123:8:123:20 | call to dup : | local_dataflow.rb:123:8:123:45 | call to tap : |
56+
| local_dataflow.rb:123:8:123:45 | call to tap : | local_dataflow.rb:123:8:123:49 | call to dup |
57+
| local_dataflow.rb:123:8:123:45 | call to tap : | local_dataflow.rb:123:8:123:49 | call to dup |
3658
nodes
3759
| local_dataflow.rb:78:12:78:20 | call to source : | semmle.label | call to source : |
3860
| local_dataflow.rb:79:25:79:25 | b | semmle.label | b |
@@ -80,6 +102,40 @@ nodes
80102
| local_dataflow.rb:107:9:107:17 | call to source : | semmle.label | call to source : |
81103
| local_dataflow.rb:108:8:108:8 | b | semmle.label | b |
82104
| local_dataflow.rb:108:8:108:8 | b | semmle.label | b |
105+
| local_dataflow.rb:112:8:112:16 | call to source : | semmle.label | call to source : |
106+
| local_dataflow.rb:112:8:112:16 | call to source : | semmle.label | call to source : |
107+
| local_dataflow.rb:112:8:112:20 | call to dup | semmle.label | call to dup |
108+
| local_dataflow.rb:112:8:112:20 | call to dup | semmle.label | call to dup |
109+
| local_dataflow.rb:113:8:113:16 | call to source : | semmle.label | call to source : |
110+
| local_dataflow.rb:113:8:113:16 | call to source : | semmle.label | call to source : |
111+
| local_dataflow.rb:113:8:113:20 | call to dup : | semmle.label | call to dup : |
112+
| local_dataflow.rb:113:8:113:20 | call to dup : | semmle.label | call to dup : |
113+
| local_dataflow.rb:113:8:113:24 | call to dup | semmle.label | call to dup |
114+
| local_dataflow.rb:113:8:113:24 | call to dup | semmle.label | call to dup |
115+
| local_dataflow.rb:117:8:117:16 | call to source : | semmle.label | call to source : |
116+
| local_dataflow.rb:117:8:117:16 | call to source : | semmle.label | call to source : |
117+
| local_dataflow.rb:117:8:117:23 | call to tap | semmle.label | call to tap |
118+
| local_dataflow.rb:117:8:117:23 | call to tap | semmle.label | call to tap |
119+
| local_dataflow.rb:118:3:118:11 | call to source : | semmle.label | call to source : |
120+
| local_dataflow.rb:118:3:118:11 | call to source : | semmle.label | call to source : |
121+
| local_dataflow.rb:118:20:118:20 | x : | semmle.label | x : |
122+
| local_dataflow.rb:118:20:118:20 | x : | semmle.label | x : |
123+
| local_dataflow.rb:118:28:118:28 | x | semmle.label | x |
124+
| local_dataflow.rb:118:28:118:28 | x | semmle.label | x |
125+
| local_dataflow.rb:119:8:119:16 | call to source : | semmle.label | call to source : |
126+
| local_dataflow.rb:119:8:119:16 | call to source : | semmle.label | call to source : |
127+
| local_dataflow.rb:119:8:119:23 | call to tap : | semmle.label | call to tap : |
128+
| local_dataflow.rb:119:8:119:23 | call to tap : | semmle.label | call to tap : |
129+
| local_dataflow.rb:119:8:119:30 | call to tap | semmle.label | call to tap |
130+
| local_dataflow.rb:119:8:119:30 | call to tap | semmle.label | call to tap |
131+
| local_dataflow.rb:123:8:123:16 | call to source : | semmle.label | call to source : |
132+
| local_dataflow.rb:123:8:123:16 | call to source : | semmle.label | call to source : |
133+
| local_dataflow.rb:123:8:123:20 | call to dup : | semmle.label | call to dup : |
134+
| local_dataflow.rb:123:8:123:20 | call to dup : | semmle.label | call to dup : |
135+
| local_dataflow.rb:123:8:123:45 | call to tap : | semmle.label | call to tap : |
136+
| local_dataflow.rb:123:8:123:45 | call to tap : | semmle.label | call to tap : |
137+
| local_dataflow.rb:123:8:123:49 | call to dup | semmle.label | call to dup |
138+
| local_dataflow.rb:123:8:123:49 | call to dup | semmle.label | call to dup |
83139
subpaths
84140
#select
85141
| local_dataflow.rb:79:25:79:25 | b | local_dataflow.rb:78:12:78:20 | call to source : | local_dataflow.rb:79:25:79:25 | b | $@ | local_dataflow.rb:78:12:78:20 | call to source : | call to source : |
@@ -103,3 +159,9 @@ subpaths
103159
| local_dataflow.rb:105:8:105:8 | a | local_dataflow.rb:104:9:104:17 | call to source : | local_dataflow.rb:105:8:105:8 | a | $@ | local_dataflow.rb:104:9:104:17 | call to source : | call to source : |
104160
| local_dataflow.rb:108:8:108:8 | b | local_dataflow.rb:106:7:106:15 | call to source : | local_dataflow.rb:108:8:108:8 | b | $@ | local_dataflow.rb:106:7:106:15 | call to source : | call to source : |
105161
| local_dataflow.rb:108:8:108:8 | b | local_dataflow.rb:107:9:107:17 | call to source : | local_dataflow.rb:108:8:108:8 | b | $@ | local_dataflow.rb:107:9:107:17 | call to source : | call to source : |
162+
| local_dataflow.rb:112:8:112:20 | call to dup | local_dataflow.rb:112:8:112:16 | call to source : | local_dataflow.rb:112:8:112:20 | call to dup | $@ | local_dataflow.rb:112:8:112:16 | call to source : | call to source : |
163+
| local_dataflow.rb:113:8:113:24 | call to dup | local_dataflow.rb:113:8:113:16 | call to source : | local_dataflow.rb:113:8:113:24 | call to dup | $@ | local_dataflow.rb:113:8:113:16 | call to source : | call to source : |
164+
| local_dataflow.rb:117:8:117:23 | call to tap | local_dataflow.rb:117:8:117:16 | call to source : | local_dataflow.rb:117:8:117:23 | call to tap | $@ | local_dataflow.rb:117:8:117:16 | call to source : | call to source : |
165+
| local_dataflow.rb:118:28:118:28 | x | local_dataflow.rb:118:3:118:11 | call to source : | local_dataflow.rb:118:28:118:28 | x | $@ | local_dataflow.rb:118:3:118:11 | call to source : | call to source : |
166+
| local_dataflow.rb:119:8:119:30 | call to tap | local_dataflow.rb:119:8:119:16 | call to source : | local_dataflow.rb:119:8:119:30 | call to tap | $@ | local_dataflow.rb:119:8:119:16 | call to source : | call to source : |
167+
| local_dataflow.rb:123:8:123:49 | call to dup | local_dataflow.rb:123:8:123:16 | call to source : | local_dataflow.rb:123:8:123:49 | call to dup | $@ | local_dataflow.rb:123:8:123:16 | call to source : | call to source : |

ruby/ql/test/library-tests/dataflow/local/local_dataflow.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,18 @@ def and_or
107107
b &&= source(8)
108108
sink(b) # $ hasValueFlow=7 hasValueFlow=8
109109
end
110+
111+
def object_dup
112+
sink(source(1).dup) # $ hasValueFlow=1
113+
sink(source(1).dup.dup) # $ hasValueFlow=1
114+
end
115+
116+
def kernel_tap
117+
sink(source(1).tap {}) # $ hasValueFlow=1
118+
source(1).tap { |x| sink(x) } # $ hasValueFlow=1
119+
sink(source(1).tap {}.tap {}) # $ hasValueFlow=1
120+
end
121+
122+
def dup_tap
123+
sink(source(1).dup.tap { |x| puts "hello" }.dup) # $ hasValueFlow=1
124+
end

0 commit comments

Comments
 (0)