@@ -9,6 +9,7 @@ private import codeql.ruby.controlflow.CfgNodes::ExprNodes
9
9
private import codeql.ruby.DataFlow
10
10
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
11
11
private import codeql.ruby.ast.internal.Constant
12
+ private import codeql.ruby.ast.internal.Module
12
13
13
14
/**
14
15
* Provides modeling for ActionController filters.
@@ -34,6 +35,17 @@ module Filters {
34
35
}
35
36
}
36
37
38
+ bindingset [ call]
39
+ pragma [ inline_late]
40
+ private ActionControllerActionMethod getADescendentAction ( MethodCallCfgNode call ) {
41
+ result = call .getExpr ( ) .getEnclosingModule ( ) .getAMethod ( )
42
+ or
43
+ exists ( ModuleBase m |
44
+ m .getModule ( ) = call .getExpr ( ) .getEnclosingModule ( ) .getModule ( ) .getAnImmediateDescendent + ( ) and
45
+ result = m .getAMethod ( )
46
+ )
47
+ }
48
+
37
49
/**
38
50
* A call to a class method that adds or removes a filter from the callback chain.
39
51
* This class exists to encapsulate common behavior between calls that
@@ -64,14 +76,7 @@ module Filters {
64
76
not exists ( this .getOnlyArgument ( ) ) and
65
77
forall ( string except | except = this .getExceptArgument ( ) | result .getName ( ) != except )
66
78
) and
67
- (
68
- result = this .getExpr ( ) .getEnclosingModule ( ) .getAMethod ( )
69
- or
70
- exists ( ModuleBase m |
71
- m .getModule ( ) = this .getExpr ( ) .getEnclosingModule ( ) .getModule ( ) .getADescendent ( ) and
72
- result = m .getAMethod ( )
73
- )
74
- )
79
+ result = getADescendentAction ( this )
75
80
}
76
81
77
82
private string getOnlyArgument ( ) {
@@ -104,8 +109,12 @@ module Filters {
104
109
105
110
StringlikeLiteralCfgNode getFilterArgument ( ) { result = this .getPositionalArgument ( _) }
106
111
112
+ string getFilterArgumentName ( ) {
113
+ result = this .getFilterArgument ( ) .getConstantValue ( ) .getStringlikeValue ( )
114
+ }
115
+
107
116
/**
108
- * Gets the callable that implements the filter with name `name` .
117
+ * Gets the callable that implements a filter registered by this call .
109
118
* This currently only finds methods in the local class or superclass.
110
119
* It doesn't handle:
111
120
* - lambdas
@@ -122,10 +131,9 @@ module Filters {
122
131
* end
123
132
* ```
124
133
*/
125
- Callable getFilterCallable ( string name ) {
126
- result .( MethodBase ) .getName ( ) = name and
127
- result .getEnclosingModule ( ) .getModule ( ) =
128
- this .getExpr ( ) .getEnclosingModule ( ) .getModule ( ) .getAnAncestor ( )
134
+ Callable getAFilterCallable ( ) {
135
+ result =
136
+ lookupMethod ( this .getExpr ( ) .getEnclosingModule ( ) .getModule ( ) , this .getFilterArgumentName ( ) )
129
137
}
130
138
}
131
139
@@ -321,7 +329,9 @@ module Filters {
321
329
322
330
string getFilterName ( ) { result = this .getConstantValue ( ) .getStringlikeValue ( ) }
323
331
324
- Callable getFilterCallable ( ) { result = call .getFilterCallable ( this .getFilterName ( ) ) }
332
+ Callable getFilterCallable ( ) {
333
+ result = call .getAFilterCallable ( ) and result .( MethodBase ) .getName ( ) = this .getFilterName ( )
334
+ }
325
335
326
336
ActionControllerActionMethod getAnAction ( ) { result = call .getAnAction ( ) }
327
337
}
@@ -387,4 +397,62 @@ module Filters {
387
397
* `pred` and `succ` may be methods bound to callbacks or controller actions.
388
398
*/
389
399
predicate next ( Method pred , Method succ ) { next ( _, pred , succ ) }
400
+
401
+ /**
402
+ * Holds if `n` is a post-update node for `self` in method `m`.
403
+ */
404
+ private predicate selfPostUpdate ( DataFlow:: PostUpdateNode n , Method m ) {
405
+ n .getPreUpdateNode ( ) .asExpr ( ) .getExpr ( ) =
406
+ any ( SelfVariableAccess self |
407
+ pragma [ only_bind_into ] ( m ) = self .getEnclosingCallable ( ) and
408
+ self .getVariable ( ) .getDeclaringScope ( ) = m
409
+ )
410
+ }
411
+
412
+ /**
413
+ * Holds if `n` is the self parameter of method `m`.
414
+ */
415
+ private predicate selfParameter ( DataFlowPrivate:: SelfParameterNode n , Method m ) {
416
+ m = n .getMethod ( )
417
+ }
418
+
419
+ /**
420
+ * A class defining additional jump steps arising from filters.
421
+ */
422
+ class FilterJumpStep extends DataFlowPrivate:: AdditionalJumpStep {
423
+ /**
424
+ * Holds if data can flow from `pred` to `succ` via a callback chain.
425
+ * `pred` is the post-update node of the self parameter in a method, and
426
+ * `succ` is the self parameter of a subsequent method that is executed as
427
+ * part of the callback chain.
428
+ */
429
+ override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
430
+ exists ( Method predMethod , Method succMethod | next ( predMethod , succMethod ) |
431
+ // Flow from a post-update node of self in `pred` to the self parameter of `succ`
432
+ //
433
+ // def a
434
+ // foo() ---------+
435
+ // @x = 1 ---+ |
436
+ // end | |
437
+ // | |
438
+ // def b <----+----+
439
+ // ...
440
+ //
441
+ selfPostUpdate ( pred , predMethod ) and
442
+ selfParameter ( succ , succMethod )
443
+ or
444
+ // Flow from the self parameter of `pred` to the self parameter of `succ`
445
+ //
446
+ // def a ---+
447
+ // ... |
448
+ // end |
449
+ // |
450
+ // def b <-+
451
+ // ...
452
+ //
453
+ selfParameter ( pred , predMethod ) and
454
+ selfParameter ( succ , succMethod )
455
+ )
456
+ }
457
+ }
390
458
}
0 commit comments