Skip to content

Commit 31336b0

Browse files
committed
add summary for the Array method on Kernel
1 parent 36b3376 commit 31336b0

File tree

3 files changed

+53
-4
lines changed

3 files changed

+53
-4
lines changed

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,35 @@ module Kernel {
197197
super.getMethodName() = ["autoload", "autoload?"]
198198
}
199199
}
200+
201+
/**
202+
* A call to `Array()`, that converts it's singular argument to an array.
203+
* This summary is based on https://ruby-doc.org/3.2.1/Kernel.html#method-i-Array
204+
*/
205+
private class KernelArraySummary extends SummarizedCallable {
206+
KernelArraySummary() { this = "Array()" }
207+
208+
override MethodCall getACallSimple() {
209+
result.getMethodName() = "Array" and
210+
// I have to have a simplified "KernelMethodCall" implementation inlined here, because relying on `UnknownMethodCall` results in non-monotonic recursion (even if using `getACall`).
211+
(
212+
result = API::getTopLevelMember("Kernel").getAMethodCall(_).asExpr().getExpr()
213+
or
214+
result.getReceiver() instanceof SelfVariableAccess
215+
)
216+
}
217+
218+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
219+
(
220+
// already an array
221+
input = "Argument[0].WithElement[0..]" and
222+
output = "ReturnValue"
223+
or
224+
// not already an array
225+
input = "Argument[0].WithoutElement[0..]" and
226+
output = "ReturnValue.Element[0]"
227+
) and
228+
preservesValue = true
229+
}
230+
}
200231
}

ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ edges
1111
| impl/unsafeCode.rb:39:14:39:14 | x : | impl/unsafeCode.rb:39:5:39:7 | [post] arr [element] : |
1212
| impl/unsafeCode.rb:47:15:47:15 | x : | impl/unsafeCode.rb:49:9:49:12 | #{...} |
1313
| impl/unsafeCode.rb:54:21:54:21 | x : | impl/unsafeCode.rb:55:22:55:22 | x |
14+
| impl/unsafeCode.rb:59:21:59:21 | x : | impl/unsafeCode.rb:60:17:60:17 | x : |
15+
| impl/unsafeCode.rb:59:24:59:24 | y : | impl/unsafeCode.rb:63:30:63:30 | y : |
16+
| impl/unsafeCode.rb:60:11:60:18 | call to Array [element 0] : | impl/unsafeCode.rb:61:10:61:12 | arr |
17+
| impl/unsafeCode.rb:60:17:60:17 | x : | impl/unsafeCode.rb:60:11:60:18 | call to Array [element 0] : |
18+
| impl/unsafeCode.rb:63:13:63:32 | call to Array [element 1] : | impl/unsafeCode.rb:63:13:63:42 | call to join : |
19+
| impl/unsafeCode.rb:63:13:63:42 | call to join : | impl/unsafeCode.rb:64:10:64:13 | arr2 |
20+
| impl/unsafeCode.rb:63:30:63:30 | y : | impl/unsafeCode.rb:63:13:63:32 | call to Array [element 1] : |
1421
nodes
1522
| impl/unsafeCode.rb:2:12:2:17 | target : | semmle.label | target : |
1623
| impl/unsafeCode.rb:3:17:3:25 | #{...} | semmle.label | #{...} |
@@ -32,6 +39,15 @@ nodes
3239
| impl/unsafeCode.rb:49:9:49:12 | #{...} | semmle.label | #{...} |
3340
| impl/unsafeCode.rb:54:21:54:21 | x : | semmle.label | x : |
3441
| impl/unsafeCode.rb:55:22:55:22 | x | semmle.label | x |
42+
| impl/unsafeCode.rb:59:21:59:21 | x : | semmle.label | x : |
43+
| impl/unsafeCode.rb:59:24:59:24 | y : | semmle.label | y : |
44+
| impl/unsafeCode.rb:60:11:60:18 | call to Array [element 0] : | semmle.label | call to Array [element 0] : |
45+
| impl/unsafeCode.rb:60:17:60:17 | x : | semmle.label | x : |
46+
| impl/unsafeCode.rb:61:10:61:12 | arr | semmle.label | arr |
47+
| impl/unsafeCode.rb:63:13:63:32 | call to Array [element 1] : | semmle.label | call to Array [element 1] : |
48+
| impl/unsafeCode.rb:63:13:63:42 | call to join : | semmle.label | call to join : |
49+
| impl/unsafeCode.rb:63:30:63:30 | y : | semmle.label | y : |
50+
| impl/unsafeCode.rb:64:10:64:13 | arr2 | semmle.label | arr2 |
3551
subpaths
3652
#select
3753
| impl/unsafeCode.rb:3:17:3:25 | #{...} | impl/unsafeCode.rb:2:12:2:17 | target : | impl/unsafeCode.rb:3:17:3:25 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:2:12:2:17 | target | library input | impl/unsafeCode.rb:3:5:3:27 | call to eval | interpreted as code |
@@ -43,3 +59,5 @@ subpaths
4359
| impl/unsafeCode.rb:44:10:44:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x : | impl/unsafeCode.rb:44:10:44:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:44:5:44:24 | call to eval | interpreted as code |
4460
| impl/unsafeCode.rb:49:9:49:12 | #{...} | impl/unsafeCode.rb:47:15:47:15 | x : | impl/unsafeCode.rb:49:9:49:12 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:47:15:47:15 | x | library input | impl/unsafeCode.rb:51:5:51:13 | call to eval | interpreted as code |
4561
| impl/unsafeCode.rb:55:22:55:22 | x | impl/unsafeCode.rb:54:21:54:21 | x : | impl/unsafeCode.rb:55:22:55:22 | x | This string concatenation which depends on $@ is later $@. | impl/unsafeCode.rb:54:21:54:21 | x | library input | impl/unsafeCode.rb:56:5:56:13 | call to eval | interpreted as code |
62+
| impl/unsafeCode.rb:61:10:61:12 | arr | impl/unsafeCode.rb:59:21:59:21 | x : | impl/unsafeCode.rb:61:10:61:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:59:21:59:21 | x | library input | impl/unsafeCode.rb:61:5:61:23 | call to eval | interpreted as code |
63+
| impl/unsafeCode.rb:64:10:64:13 | arr2 | impl/unsafeCode.rb:59:24:59:24 | y : | impl/unsafeCode.rb:64:10:64:13 | arr2 | This array which depends on $@ is later $@. | impl/unsafeCode.rb:59:24:59:24 | y | library input | impl/unsafeCode.rb:64:5:64:25 | call to eval | interpreted as code |

ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ def string_concat(x)
5757
end
5858

5959
def join_indirect(x, y)
60-
arr = Array("foo = ", x)
61-
eval(arr.join(" ")) # NOT OK - but not currently flagged by the query
60+
arr = Array(x)
61+
eval(arr.join(" ")) # NOT OK
6262

63-
arr2 = [Array("foo = ", y).join(" ")]
64-
eval(arr2.join("\n")) # NOT OK - but not currently flagged by the query
63+
arr2 = [Array(["foo = ", y]).join(" ")]
64+
eval(arr2.join("\n")) # NOT OK
6565
end
6666
end

0 commit comments

Comments
 (0)