Skip to content

Commit 03fff27

Browse files
committed
Add suggestions to fix FileJoinSanitizer
1 parent 0d8c820 commit 03fff27

File tree

6 files changed

+20
-24
lines changed

6 files changed

+20
-24
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ module File {
133133
}
134134

135135
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
136-
input = "Argument[0..]" and
136+
input = "Argument[0,1..]" and
137137
output = "ReturnValue" and
138138
preservesValue = false
139139
}

ruby/ql/lib/codeql/ruby/security/KernelOpenQuery.qll

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ private import codeql.ruby.DataFlow
77
private import codeql.ruby.AST
88
private import codeql.ruby.ApiGraphs
99
private import codeql.ruby.frameworks.core.Kernel::Kernel
10+
private import codeql.ruby.frameworks.Files
1011

1112
/** A call to a method that might access a file or start a process. */
1213
class AmbiguousPathCall extends DataFlow::CallNode {
@@ -16,23 +17,12 @@ class AmbiguousPathCall extends DataFlow::CallNode {
1617
this.(KernelMethodCall).getMethodName() = "open" and
1718
name = "Kernel.open"
1819
or
19-
methodCallOnlyOnIO(this, "read") and
20-
name = "IO.read"
21-
or
22-
methodCallOnlyOnIO(this, "write") and
23-
name = "IO.write"
24-
or
25-
methodCallOnlyOnIO(this, "binread") and
26-
name = "IO.binread"
27-
or
28-
methodCallOnlyOnIO(this, "binwrite") and
29-
name = "IO.binwrite"
30-
or
31-
methodCallOnlyOnIO(this, "foreach") and
32-
name = "IO.foreach"
33-
or
34-
methodCallOnlyOnIO(this, "readlines") and
35-
name = "IO.readlines"
20+
exists(string methodName |
21+
methodName = ["read", "write", "binread", "binwrite", "foreach", "readlines"]
22+
|
23+
methodCallOnlyOnIO(this, methodName) and
24+
name = "IO." + methodName
25+
)
3626
or
3727
this = API::getTopLevelMember("URI").getAMethodCall("open") and
3828
name = "URI.open"
@@ -75,11 +65,9 @@ private predicate methodCallOnlyOnIO(DataFlow::CallNode node, string methodName)
7565
abstract class Sanitizer extends DataFlow::Node { }
7666

7767
/**
78-
* If a File.join is performed the resulting string will not start with a pipe |
68+
* If a `File.join` is performed the resulting string will not start with a pipe `|`.
7969
* This is true as long the tainted data doesn't flow into the first argument.
8070
*/
81-
private class FileJoinCall extends Sanitizer, DataFlow::ExprNode {
82-
FileJoinCall() {
83-
this = API::getTopLevelMember("File").getAMethodCall("join").getArgument(any(int i | i > 0))
84-
}
71+
private class FileJoinSanitizer extends Sanitizer {
72+
FileJoinSanitizer() { this = any(File::FileJoinSummary s).getParameter("1..") }
8573
}

ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ edges
99
| KernelOpen.rb:3:12:3:24 | ...[...] : | KernelOpen.rb:10:18:10:21 | file |
1010
| KernelOpen.rb:3:12:3:24 | ...[...] : | KernelOpen.rb:11:14:11:17 | file |
1111
| KernelOpen.rb:3:12:3:24 | ...[...] : | KernelOpen.rb:13:23:13:26 | file : |
12+
| KernelOpen.rb:3:12:3:24 | ...[...] : | KernelOpen.rb:26:10:26:13 | file |
1213
| KernelOpen.rb:13:23:13:26 | file : | KernelOpen.rb:13:13:13:31 | call to join |
1314
nodes
1415
| KernelOpen.rb:3:12:3:17 | call to params : | semmle.label | call to params : |
@@ -23,6 +24,7 @@ nodes
2324
| KernelOpen.rb:11:14:11:17 | file | semmle.label | file |
2425
| KernelOpen.rb:13:13:13:31 | call to join | semmle.label | call to join |
2526
| KernelOpen.rb:13:23:13:26 | file : | semmle.label | file : |
27+
| KernelOpen.rb:26:10:26:13 | file | semmle.label | file |
2628
subpaths
2729
#select
2830
| KernelOpen.rb:4:10:4:13 | file | KernelOpen.rb:3:12:3:17 | call to params : | KernelOpen.rb:4:10:4:13 | file | This call to Kernel.open depends on a $@. Consider replacing it with File.open. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value |
@@ -34,3 +36,4 @@ subpaths
3436
| KernelOpen.rb:10:18:10:21 | file | KernelOpen.rb:3:12:3:17 | call to params : | KernelOpen.rb:10:18:10:21 | file | This call to IO.readlines depends on a $@. Consider replacing it with File.readlines. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value |
3537
| KernelOpen.rb:11:14:11:17 | file | KernelOpen.rb:3:12:3:17 | call to params : | KernelOpen.rb:11:14:11:17 | file | This call to URI.open depends on a $@. Consider replacing it with URI(<uri>).open. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value |
3638
| KernelOpen.rb:13:13:13:31 | call to join | KernelOpen.rb:3:12:3:17 | call to params : | KernelOpen.rb:13:13:13:31 | call to join | This call to IO.read depends on a $@. Consider replacing it with File.read. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value |
39+
| KernelOpen.rb:26:10:26:13 | file | KernelOpen.rb:3:12:3:17 | call to params : | KernelOpen.rb:26:10:26:13 | file | This call to Kernel.open depends on a $@. Consider replacing it with File.open. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value |

ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def create
1010
IO.readlines(file) # BAD
1111
URI.open(file) # BAD
1212

13-
IO.read(File.join(file, "")) # BAD - file as first argument to File.join
13+
IO.read(File.join(file, "")) # BAD - file as first argument to File.join
1414
IO.read(File.join("", file)) # GOOD - file path is sanitised by guard
1515

1616
File.open(file).read # GOOD
@@ -22,5 +22,7 @@ def create
2222
if %w(some/const/1.txt some/const/2.txt).include? file
2323
IO.read(file) # GOOD - file path is sanitised by guard
2424
end
25+
26+
open(file) # BAD - sanity check to verify that file was not mistakenly marked as sanitized
2527
end
2628
end

ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
| NonConstantKernelOpen.rb:11:5:11:18 | call to open | Call to URI.open with a non-constant value. Consider replacing it with URI(<uri>).open. |
99
| NonConstantKernelOpen.rb:15:5:15:21 | call to open | Call to Kernel.open with a non-constant value. Consider replacing it with File.open. |
1010
| NonConstantKernelOpen.rb:25:5:25:33 | call to open | Call to Kernel.open with a non-constant value. Consider replacing it with File.open. |
11+
| NonConstantKernelOpen.rb:33:5:33:14 | call to open | Call to Kernel.open with a non-constant value. Consider replacing it with File.open. |

ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,7 @@ def create
2929
IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :foo; puts :bar; puts :baz'") {|x| a << x } # GOOD
3030

3131
IO.write(File.join("foo", "bar.txt"), "bar") # GOOD
32+
33+
open(file) # BAD - sanity check to verify that file was not mistakenly marked as sanitized
3234
end
3335
end

0 commit comments

Comments
 (0)