Skip to content

Commit e4f801b

Browse files
authored
Merge pull request #7886 from github/hmac/split-ruby-std-library
Ruby: split standard library models into multiple files
2 parents a448db1 + 9a60c7e commit e4f801b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+945
-612
lines changed

ruby/ql/lib/codeql/ruby/Frameworks.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
* Helper file that imports all framework modeling.
33
*/
44

5+
private import codeql.ruby.frameworks.Core
56
private import codeql.ruby.frameworks.ActionController
67
private import codeql.ruby.frameworks.ActiveRecord
78
private import codeql.ruby.frameworks.ActiveStorage
89
private import codeql.ruby.frameworks.ActionView
910
private import codeql.ruby.frameworks.ActiveSupport
1011
private import codeql.ruby.frameworks.GraphQL
1112
private import codeql.ruby.frameworks.Rails
12-
private import codeql.ruby.frameworks.StandardLibrary
13+
private import codeql.ruby.frameworks.Stdlib
1314
private import codeql.ruby.frameworks.Files
1415
private import codeql.ruby.frameworks.HttpClients
1516
private import codeql.ruby.frameworks.XmlParsing

ruby/ql/lib/codeql/ruby/ast/Call.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ class MethodCall extends Call instanceof MethodCallImpl {
116116
}
117117
}
118118

119+
/**
120+
* A `Method` call that has no known target.
121+
* These will typically be calls to methods inherited from a superclass.
122+
* TODO: When API Graphs is able to resolve calls to methods like `Kernel.send`
123+
* this class is no longer necessary and should be removed.
124+
*/
125+
class UnknownMethodCall extends MethodCall {
126+
UnknownMethodCall() { not exists(this.(Call).getATarget()) }
127+
}
128+
119129
/**
120130
* A call to a setter method.
121131
* ```rb

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/**
2+
* Provides modeling for the `ActionController` library.
3+
*/
4+
15
private import codeql.ruby.AST
26
private import codeql.ruby.Concepts
37
private import codeql.ruby.controlflow.CfgNodes
@@ -66,10 +70,14 @@ class ActionControllerActionMethod extends Method, HTTP::Server::RequestHandler:
6670
/** Gets a call to render from within this method. */
6771
RenderCall getARenderCall() { result.getParent+() = this }
6872

69-
// TODO: model the implicit render call when a path through the method does
70-
// not end at an explicit render or redirect
71-
/** Gets the controller class containing this method. */
72-
ActionControllerControllerClass getControllerClass() { result = controllerClass }
73+
/**
74+
* Gets the controller class containing this method.
75+
*/
76+
ActionControllerControllerClass getControllerClass() {
77+
// TODO: model the implicit render call when a path through the method does
78+
// not end at an explicit render or redirect
79+
result = controllerClass
80+
}
7381

7482
/**
7583
* Gets a route to this handler, if one exists.
@@ -101,6 +109,9 @@ private class ActionControllerContextCall extends MethodCall {
101109
this.getEnclosingModule() = controllerClass
102110
}
103111

112+
/**
113+
* Gets the controller class containing this method.
114+
*/
104115
ActionControllerControllerClass getControllerClass() { result = controllerClass }
105116
}
106117

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/**
2+
* Provides modeling for the `ActionView` library.
3+
*/
4+
15
private import codeql.ruby.AST
26
private import codeql.ruby.Concepts
37
private import codeql.ruby.controlflow.CfgNodes
@@ -6,6 +10,9 @@ private import codeql.ruby.dataflow.RemoteFlowSources
610
private import codeql.ruby.ast.internal.Module
711
private import ActionController
812

13+
/**
14+
* Holds if this AST node is in a context where `ActionView` methods are available.
15+
*/
916
predicate inActionViewContext(AstNode n) {
1017
// Within a template
1118
n.getLocation().getFile() instanceof ErbFile
@@ -33,6 +40,9 @@ abstract class HtmlEscapeCall extends MethodCall {
3340
HtmlEscapeCall() { this.getMethodName() = ["html_escape", "html_escape_once", "h"] }
3441
}
3542

43+
/**
44+
* A call to a Rails method that escapes HTML.
45+
*/
3646
class RailsHtmlEscaping extends Escaping::Range, DataFlow::CallNode {
3747
RailsHtmlEscaping() { this.asExpr().getExpr() instanceof HtmlEscapeCall }
3848

@@ -55,6 +65,9 @@ private class ActionViewContextCall extends MethodCall {
5565
inActionViewContext(this)
5666
}
5767

68+
/**
69+
* Holds if this call is located inside an ERb template.
70+
*/
5871
predicate isInErbFile() { this.getLocation().getFile() instanceof ErbFile }
5972
}
6073

@@ -132,6 +145,9 @@ private class ActionViewRenderToCall extends ActionViewContextCall, RenderToCall
132145
class LinkToCall extends ActionViewContextCall {
133146
LinkToCall() { this.getMethodName() = "link_to" }
134147

148+
/**
149+
* Gets the path argument to the call.
150+
*/
135151
Expr getPathArgument() {
136152
// When `link_to` is called with a block, it uses the first argument as the
137153
// path, and otherwise the second argument.

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
/**
2+
* Provides modeling for the `ActiveRecord` library.
3+
*/
4+
15
private import codeql.ruby.AST
26
private import codeql.ruby.Concepts
37
private import codeql.ruby.controlflow.CfgNodes
48
private import codeql.ruby.DataFlow
59
private import codeql.ruby.dataflow.internal.DataFlowDispatch
610
private import codeql.ruby.ast.internal.Module
711
private import codeql.ruby.ApiGraphs
8-
private import codeql.ruby.frameworks.StandardLibrary
12+
private import codeql.ruby.frameworks.Stdlib
13+
private import codeql.ruby.frameworks.Core
914

1015
/// See https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html
1116
private string activeRecordPersistenceInstanceMethodName() {
@@ -182,6 +187,9 @@ class PotentiallyUnsafeSqlExecutingMethodCall extends ActiveRecordModelClassMeth
182187
)
183188
}
184189

190+
/**
191+
* Gets the SQL fragment argument of this method call.
192+
*/
185193
Expr getSqlFragmentSinkArgument() { result = sqlFragmentExpr }
186194
}
187195

@@ -207,6 +215,9 @@ class ActiveRecordSqlExecutionRange extends SqlExecution::Range {
207215
*/
208216
abstract class ActiveRecordModelInstantiation extends OrmInstantiation::Range,
209217
DataFlow::LocalSourceNode {
218+
/**
219+
* Gets the `ActiveRecordModelClass` that this instance belongs to.
220+
*/
210221
abstract ActiveRecordModelClass getClass();
211222

212223
bindingset[methodName]

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/**
2+
* Provides modeling for the `ActiveStorage` library.
3+
*/
4+
15
private import codeql.ruby.AST
26
private import codeql.ruby.ApiGraphs
37
private import codeql.ruby.Concepts

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
* https://rubygems.org/gems/activesupport
44
*/
55

6-
import codeql.ruby.Concepts
7-
import codeql.ruby.DataFlow
8-
import codeql.ruby.frameworks.StandardLibrary
6+
private import ruby
7+
private import codeql.ruby.Concepts
8+
private import codeql.ruby.DataFlow
99

1010
/**
1111
* Modeling for `ActiveSupport`.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Provides modeling for the Ruby core libraries.
3+
*/
4+
5+
private import codeql.ruby.Concepts
6+
private import codeql.ruby.DataFlow
7+
private import codeql.ruby.dataflow.FlowSummary
8+
import core.BasicObject::BasicObject
9+
import core.Object::Object
10+
import core.Kernel::Kernel
11+
import core.Module
12+
import core.Array
13+
import core.Regexp
14+
15+
/**
16+
* A system command executed via subshell literal syntax.
17+
* E.g.
18+
* ```ruby
19+
* `cat foo.txt`
20+
* %x(cat foo.txt)
21+
* %x[cat foo.txt]
22+
* %x{cat foo.txt}
23+
* %x/cat foo.txt/
24+
* ```
25+
*/
26+
class SubshellLiteralExecution extends SystemCommandExecution::Range {
27+
SubshellLiteral literal;
28+
29+
SubshellLiteralExecution() { this.asExpr().getExpr() = literal }
30+
31+
override DataFlow::Node getAnArgument() { result.asExpr().getExpr() = literal.getComponent(_) }
32+
33+
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getAnArgument() }
34+
}
35+
36+
/**
37+
* A system command executed via shell heredoc syntax.
38+
* E.g.
39+
* ```ruby
40+
* <<`EOF`
41+
* cat foo.text
42+
* EOF
43+
* ```
44+
*/
45+
class SubshellHeredocExecution extends SystemCommandExecution::Range {
46+
HereDoc heredoc;
47+
48+
SubshellHeredocExecution() { this.asExpr().getExpr() = heredoc and heredoc.isSubShell() }
49+
50+
override DataFlow::Node getAnArgument() { result.asExpr().getExpr() = heredoc.getComponent(_) }
51+
52+
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getAnArgument() }
53+
}
54+
55+
private class SplatSummary extends SummarizedCallable {
56+
SplatSummary() { this = "*(splat)" }
57+
58+
override SplatExpr getACall() { any() }
59+
60+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
61+
(
62+
// *1 = [1]
63+
input = "Receiver" and
64+
output = "ArrayElement[0] of ReturnValue"
65+
or
66+
// *[1] = [1]
67+
input = "Receiver" and
68+
output = "ReturnValue"
69+
) and
70+
preservesValue = true
71+
}
72+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ private import ruby
66
private import codeql.ruby.Concepts
77
private import codeql.ruby.ApiGraphs
88
private import codeql.ruby.DataFlow
9-
private import codeql.ruby.frameworks.StandardLibrary
9+
private import codeql.ruby.frameworks.Core
1010
private import codeql.ruby.dataflow.FlowSummary
1111

1212
private DataFlow::Node ioInstanceInstantiation() {

0 commit comments

Comments
 (0)