Skip to content

Commit 893ca5a

Browse files
authored
Merge pull request github#353 from github/rc/3.3
Merge rc/3.3 into main
2 parents 01819cd + dc8399f commit 893ca5a

File tree

6 files changed

+120
-61
lines changed

6 files changed

+120
-61
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Follow the steps below to help other users understand what your query does, and
3131

3232
2. **Format your code correctly**
3333

34-
All of the standard CodeQL queries and libraries are uniformly formatted for clarity and consistency, so we strongly recommend that all contributions follow the same formatting guidelines. If you use the CodeQL extension for Visual Studio Code, you can auto-format your query using the [Format Document command](https://help.semmle.com/codeql/codeql-for-vscode/procedures/about-codeql-for-vscode.html). For more information, see the [QL style guide](https://github.com/github/codeql/blob/main/docs/ql-style-guide.md).
34+
All of the standard CodeQL queries and libraries are uniformly formatted for clarity and consistency, so we strongly recommend that all contributions follow the same formatting guidelines. If you use the CodeQL extension for Visual Studio Code, you can auto-format your query using the [Format Document command](https://code.visualstudio.com/docs/editor/codebasics#_formatting). For more information, see the [QL style guide](https://github.com/github/codeql/blob/main/docs/ql-style-guide.md).
3535

3636
3. **Make sure your query has the correct metadata**
3737

ql/docs/experimental.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Experimental queries and libraries may not be actively maintained as the standar
2121

2222
3. **Formatting**
2323

24-
- The queries and libraries must be [autoformatted](https://help.semmle.com/codeql/codeql-for-vscode/reference/editor.html#autoformatting).
24+
- The queries and libraries must be [autoformatted](https://code.visualstudio.com/docs/editor/codebasics#_formatting).
2525

2626
4. **Compilation**
2727

ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Node extends TNode {
3232
* The location spans column `startcolumn` of line `startline` to
3333
* column `endcolumn` of line `endline` in file `filepath`.
3434
* For more information, see
35-
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
35+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
3636
*/
3737
predicate hasLocationInfo(
3838
string filepath, int startline, int startcolumn, int endline, int endcolumn

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

Lines changed: 113 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -123,79 +123,137 @@ private module Shared {
123123
}
124124

125125
/**
126-
* An additional step that is preserves dataflow in the context of XSS.
126+
* Holds if `call` is a method call in ERB file `erb`, targeting a method
127+
* named `name`.
127128
*/
128-
predicate isAdditionalXSSFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
129-
// node1 is a `locals` argument to a render call...
130-
exists(RenderCall call, Pair kvPair, string hashKey |
129+
pragma[noinline]
130+
private predicate isMethodCall(MethodCall call, string name, ErbFile erb) {
131+
name = call.getMethodName() and
132+
erb = call.getLocation().getFile()
133+
}
134+
135+
/**
136+
* Holds if some render call passes `value` for `hashKey` in the `locals`
137+
* argument, in ERB file `erb`.
138+
*/
139+
pragma[noinline]
140+
private predicate renderCallLocals(string hashKey, Expr value, ErbFile erb) {
141+
exists(RenderCall call, Pair kvPair |
131142
call.getLocals().getAKeyValuePair() = kvPair and
132-
kvPair.getValue() = node1.asExpr().getExpr() and
133-
kvPair.getKey().(StringlikeLiteral).getValueText() = hashKey and
134-
// `node2` appears in the rendered template file
135-
call.getTemplateFile() = node2.getLocation().getFile() and
136-
(
137-
// node2 is an element reference against `local_assigns`
138-
exists(
139-
CfgNodes::ExprNodes::ElementReferenceCfgNode refNode, DataFlow::Node argNode,
140-
CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode
141-
|
142-
refNode = node2.asExpr() and
143-
argNode.asExpr() = refNode.getArgument(0) and
144-
refNode.getReceiver().getExpr().(MethodCall).getMethodName() = "local_assigns" and
145-
argNode.getALocalSource() = DataFlow::exprNode(strNode) and
146-
strNode.getExpr().getValueText() = hashKey
147-
)
148-
or
149-
// ...node2 is a "method call" to a "method" with `hashKey` as its name
150-
// TODO: This may be a variable read in reality that we interpret as a method call
151-
exists(MethodCall varAcc |
152-
varAcc = node2.asExpr().(CfgNodes::ExprNodes::MethodCallCfgNode).getExpr() and
153-
varAcc.getMethodName() = hashKey
154-
)
155-
)
143+
kvPair.getValue() = value and
144+
kvPair.getKey().getValueText() = hashKey and
145+
call.getTemplateFile() = erb
156146
)
157-
or
158-
// instance variables in the controller
159-
exists(
160-
ActionControllerActionMethod action, VariableReadAccess viewVarRead, AssignExpr ae,
161-
FinalInstanceVarWrite controllerVarWrite
147+
}
148+
149+
pragma[noinline]
150+
private predicate isFlowFromLocals0(
151+
CfgNodes::ExprNodes::ElementReferenceCfgNode refNode, string hashKey, ErbFile erb
152+
) {
153+
exists(DataFlow::Node argNode, CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode |
154+
argNode.asExpr() = refNode.getArgument(0) and
155+
refNode.getReceiver().getExpr().(MethodCall).getMethodName() = "local_assigns" and
156+
argNode.getALocalSource() = DataFlow::exprNode(strNode) and
157+
strNode.getExpr().getValueText() = hashKey and
158+
erb = refNode.getFile()
159+
)
160+
}
161+
162+
private predicate isFlowFromLocals(DataFlow::Node node1, DataFlow::Node node2) {
163+
exists(string hashKey, ErbFile erb |
164+
// node1 is a `locals` argument to a render call...
165+
renderCallLocals(hashKey, node1.asExpr().getExpr(), erb)
162166
|
163-
viewVarRead = node2.asExpr().(CfgNodes::ExprNodes::VariableReadAccessCfgNode).getExpr() and
164-
action.getDefaultTemplateFile() = viewVarRead.getLocation().getFile() and
167+
// node2 is an element reference against `local_assigns`
168+
isFlowFromLocals0(node2.asExpr(), hashKey, erb)
169+
or
170+
// ...node2 is a "method call" to a "method" with `hashKey` as its name
171+
// TODO: This may be a variable read in reality that we interpret as a method call
172+
isMethodCall(node2.asExpr().getExpr(), hashKey, erb)
173+
)
174+
}
175+
176+
/**
177+
* Holds if `action` contains an assignment of `value` to an instance
178+
* variable named `name`, in ERB file `erb`.
179+
*/
180+
pragma[noinline]
181+
private predicate actionAssigns(
182+
ActionControllerActionMethod action, string name, Expr value, ErbFile erb
183+
) {
184+
exists(AssignExpr ae, FinalInstanceVarWrite controllerVarWrite |
185+
action.getDefaultTemplateFile() = erb and
186+
ae.getParent+() = action and
187+
ae = controllerVarWrite.getAnAssignExpr() and
188+
name = controllerVarWrite.getVariable().getName() and
189+
value = ae.getRightOperand()
190+
)
191+
}
192+
193+
pragma[noinline]
194+
private predicate isVariableReadAccess(VariableReadAccess viewVarRead, string name, ErbFile erb) {
195+
erb = viewVarRead.getLocation().getFile() and
196+
viewVarRead.getVariable().getName() = name
197+
}
198+
199+
private predicate isFlowFromControllerInstanceVariable(DataFlow::Node node1, DataFlow::Node node2) {
200+
// instance variables in the controller
201+
exists(ActionControllerActionMethod action, string name, ErbFile template |
165202
// match read to write on variable name
166-
viewVarRead.getVariable().getName() = controllerVarWrite.getVariable().getName() and
203+
actionAssigns(action, name, node1.asExpr().getExpr(), template) and
167204
// propagate taint from assignment RHS expr to variable read access in view
168-
ae = controllerVarWrite.getAnAssignExpr() and
169-
node1.asExpr().getExpr() = ae.getRightOperand() and
170-
ae.getParent+() = action
205+
isVariableReadAccess(node2.asExpr().getExpr(), name, template)
171206
)
172-
or
207+
}
208+
209+
/**
210+
* Holds if `helperMethod` is a helper method named `name` that is associated
211+
* with ERB file `erb`.
212+
*/
213+
pragma[noinline]
214+
private predicate isHelperMethod(
215+
ActionControllerHelperMethod helperMethod, string name, ErbFile erb
216+
) {
217+
helperMethod.getName() = name and
218+
helperMethod.getControllerClass() = getAssociatedControllerClass(erb)
219+
}
220+
221+
private predicate isFlowIntoHelperMethod(DataFlow::Node node1, DataFlow::Node node2) {
173222
// flow from template into controller helper method
174223
exists(
175-
ErbFile template, ActionControllerHelperMethod helperMethod,
224+
ErbFile template, ActionControllerHelperMethod helperMethod, string name,
176225
CfgNodes::ExprNodes::MethodCallCfgNode helperMethodCall, int argIdx
177226
|
178-
template = node1.getLocation().getFile() and
179-
helperMethod.getName() = helperMethodCall.getExpr().getMethodName() and
180-
helperMethod.getControllerClass() = getAssociatedControllerClass(template) and
181-
helperMethodCall.getArgument(argIdx) = node1.asExpr() and
182-
helperMethod.getParameter(argIdx) = node2.asExpr().getExpr()
227+
isHelperMethod(helperMethod, name, template) and
228+
isMethodCall(helperMethodCall.getExpr(), name, template) and
229+
helperMethodCall.getArgument(pragma[only_bind_into](argIdx)) = node1.asExpr() and
230+
helperMethod.getParameter(pragma[only_bind_into](argIdx)) = node2.asExpr().getExpr()
183231
)
184-
or
232+
}
233+
234+
private predicate isFlowFromHelperMethod(DataFlow::Node node1, DataFlow::Node node2) {
185235
// flow out of controller helper method into template
186-
exists(
187-
ErbFile template, ActionControllerHelperMethod helperMethod,
188-
CfgNodes::ExprNodes::MethodCallCfgNode helperMethodCall
189-
|
190-
template = node2.getLocation().getFile() and
191-
helperMethod.getName() = helperMethodCall.getExpr().getMethodName() and
192-
helperMethod.getControllerClass() = getAssociatedControllerClass(template) and
236+
exists(ErbFile template, ActionControllerHelperMethod helperMethod, string name |
193237
// `node1` is an expr node that may be returned by the helper method
194238
exprNodeReturnedFrom(node1, helperMethod) and
195239
// `node2` is a call to the helper method
196-
node2.asExpr() = helperMethodCall
240+
isHelperMethod(helperMethod, name, template) and
241+
isMethodCall(node2.asExpr().getExpr(), name, template)
197242
)
198243
}
244+
245+
/**
246+
* An additional step that is preserves dataflow in the context of XSS.
247+
*/
248+
predicate isAdditionalXSSFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
249+
isFlowFromLocals(node1, node2)
250+
or
251+
isFlowFromControllerInstanceVariable(node1, node2)
252+
or
253+
isFlowIntoHelperMethod(node1, node2)
254+
or
255+
isFlowFromHelperMethod(node1, node2)
256+
}
199257
}
200258

201259
/**

ql/src/AlertSuppression.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class SuppressionScope extends @ruby_token_comment {
6363
* The location spans column `startcolumn` of line `startline` to
6464
* column `endcolumn` of line `endline` in file `filepath`.
6565
* For more information, see
66-
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
66+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
6767
*/
6868
predicate hasLocationInfo(
6969
string filepath, int startline, int startcolumn, int endline, int endcolumn

scripts/identical-files.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
],
1010
"DataFlow": [
1111
"codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll",
12-
"ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll"
12+
"ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
13+
"ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll"
1314
],
1415
"DataFlow2": [
1516
"codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll",
@@ -48,4 +49,4 @@
4849
"codeql/cpp/ql/lib/tutorial.qll",
4950
"ql/lib/tutorial.qll"
5051
]
51-
}
52+
}

0 commit comments

Comments
 (0)