Skip to content

Commit f3741ff

Browse files
committed
changes based on review
1 parent 7797211 commit f3741ff

File tree

4 files changed

+27
-8
lines changed

4 files changed

+27
-8
lines changed

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,17 @@ private import codeql.ruby.ApiGraphs
88

99
/** Provides modeling for the `Gem` module and `.gemspec` files. */
1010
module Gem {
11-
/** A .gemspec file that lists properties of a Ruby gem. */
11+
/**
12+
* A .gemspec file that lists properties of a Ruby gem.
13+
* The contents of a .gemspec file generally look like:
14+
* ```Ruby
15+
* Gem::Specification.new do |s|
16+
* s.name = 'library-name'
17+
* s.require_path = "lib"
18+
* # more properties
19+
* end
20+
* ```
21+
*/
1222
class GemSpec instanceof File {
1323
API::Node specCall;
1424

@@ -25,13 +35,13 @@ module Gem {
2535
* Gets a value of the `name` property of this .gemspec file.
2636
* These properties are set using the `Gem::Specification.new` method.
2737
*/
28-
private Expr getSpecProperty(string key) {
38+
private Expr getSpecProperty(string name) {
2939
exists(Expr rhs |
3040
rhs =
3141
specCall
3242
.getBlock()
3343
.getParameter(0)
34-
.getMethod(key + "=")
44+
.getMethod(name + "=")
3545
.getParameter(0)
3646
.asSink()
3747
.asExpr()
@@ -57,14 +67,14 @@ module Gem {
5767
result = "lib" // the default is "lib"
5868
}
5969

60-
/** Gets a file that is loaded when the gem is required. */
61-
private File getAnRequiredFile() {
70+
/** Gets a file that could be loaded when the gem is required. */
71+
private File getAPossiblyRequiredFile() {
6272
result = File.super.getParentContainer().getFolder(getARequirePath()).getAChildContainer*()
6373
}
6474

6575
/** Gets a class/module that is exported by this gem. */
6676
private ModuleBase getAPublicModule() {
67-
result.(Toplevel).getLocation().getFile() = getAnRequiredFile()
77+
result.(Toplevel).getLocation().getFile() = getAPossiblyRequiredFile()
6878
or
6979
result = getAPublicModule().getAModule()
7080
or

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ module UnsafeShellCommandConstruction {
6565
* A string constructed from a string-literal (e.g. `"foo #{sink}"`),
6666
* where the resulting string ends up being executed as a shell command.
6767
*/
68-
class StringFormatAsSink extends Sink {
68+
class StringInterpolationAsSink extends Sink {
6969
Concepts::SystemCommandExecution s;
7070
Ast::StringLiteral lit;
7171

72-
StringFormatAsSink() {
72+
StringInterpolationAsSink() {
7373
isUsedAsShellCommand(any(DataFlow::Node n | n.asExpr().getExpr() = lit), s) and
7474
this.asExpr().getExpr() = lit.getComponent(_)
7575
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edges
88
| impl/unsafeShell.rb:23:15:23:23 | file_path : | impl/unsafeShell.rb:26:19:26:30 | #{...} |
99
| impl/unsafeShell.rb:33:12:33:17 | target : | impl/unsafeShell.rb:34:19:34:27 | #{...} |
1010
| impl/unsafeShell.rb:37:10:37:10 | x : | impl/unsafeShell.rb:38:19:38:22 | #{...} |
11+
| impl/unsafeShell.rb:47:16:47:21 | target : | impl/unsafeShell.rb:48:19:48:27 | #{...} |
1112
nodes
1213
| impl/sub/notImported.rb:2:12:2:17 | target : | semmle.label | target : |
1314
| impl/sub/notImported.rb:3:19:3:27 | #{...} | semmle.label | #{...} |
@@ -27,6 +28,8 @@ nodes
2728
| impl/unsafeShell.rb:34:19:34:27 | #{...} | semmle.label | #{...} |
2829
| impl/unsafeShell.rb:37:10:37:10 | x : | semmle.label | x : |
2930
| impl/unsafeShell.rb:38:19:38:22 | #{...} | semmle.label | #{...} |
31+
| impl/unsafeShell.rb:47:16:47:21 | target : | semmle.label | target : |
32+
| impl/unsafeShell.rb:48:19:48:27 | #{...} | semmle.label | #{...} |
3033
subpaths
3134
#select
3235
| impl/sub/notImported.rb:3:14:3:28 | "cat #{...}" | impl/sub/notImported.rb:2:12:2:17 | target : | impl/sub/notImported.rb:3:19:3:27 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/sub/notImported.rb:2:12:2:17 | target | library input | impl/sub/notImported.rb:3:5:3:34 | call to popen | shell command |
@@ -38,3 +41,4 @@ subpaths
3841
| impl/unsafeShell.rb:26:14:26:31 | "cat #{...}" | impl/unsafeShell.rb:23:15:23:23 | file_path : | impl/unsafeShell.rb:26:19:26:30 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:23:15:23:23 | file_path | library input | impl/unsafeShell.rb:26:5:26:37 | call to popen | shell command |
3942
| impl/unsafeShell.rb:34:14:34:28 | "cat #{...}" | impl/unsafeShell.rb:33:12:33:17 | target : | impl/unsafeShell.rb:34:19:34:27 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:33:12:33:17 | target | library input | impl/unsafeShell.rb:34:5:34:34 | call to popen | shell command |
4043
| impl/unsafeShell.rb:38:14:38:23 | "cat #{...}" | impl/unsafeShell.rb:37:10:37:10 | x : | impl/unsafeShell.rb:38:19:38:22 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:37:10:37:10 | x | library input | impl/unsafeShell.rb:38:5:38:29 | call to popen | shell command |
44+
| impl/unsafeShell.rb:48:14:48:28 | "cat #{...}" | impl/unsafeShell.rb:47:16:47:21 | target : | impl/unsafeShell.rb:48:19:48:27 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:47:16:47:21 | target | library input | impl/unsafeShell.rb:48:5:48:34 | call to popen | shell command |

ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/unsafeShell.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,9 @@ def id(x)
4242
def thisIsSafe()
4343
IO.popen("echo #{id('foo')}", "w") # OK - only using constants.
4444
end
45+
46+
# class methods
47+
def self.foo(target)
48+
IO.popen("cat #{target}", "w") # NOT OK
49+
end
4550
end

0 commit comments

Comments
 (0)