Add flow steps and sanitizers for permit calls

This commit is contained in:
Joe Farebrother
2024-04-10 21:47:07 +01:00
parent 976ca48317
commit 0a3d73d902
3 changed files with 78 additions and 22 deletions

View File

@@ -41,8 +41,9 @@ module MassAssignment {
private class RemoteSource extends Source instanceof RemoteFlowSource { }
/** A call to `permit!`, which permits each key of its receiver. */
private class PermitBangCall extends MassPermit instanceof DataFlow::CallNode {
PermitBangCall() { this.asExpr().getExpr().(MethodCall).getMethodName() = "permit!" }
PermitBangCall() { this.(DataFlow::CallNode).getMethodName() = "permit!" }
override DataFlow::Node getParamsArgument() { result = this.(DataFlow::CallNode).getReceiver() }
@@ -52,4 +53,45 @@ module MassAssignment {
result.(DataFlow::PostUpdateNode).getPreUpdateNode() = this.getParamsArgument()
}
}
/** Holds if `h` is an empty hash or contains an empty hash at one if its (possibly nested) values. */
private predicate hasEmptyHash(Expr e) {
e instanceof HashLiteral and
count(e.(HashLiteral).getAKeyValuePair()) = 0
or
hasEmptyHash(e.(HashLiteral).getAKeyValuePair().getValue())
or
hasEmptyHash(e.(Pair).getValue())
or
hasEmptyHash(e.(ArrayLiteral).getAnElement())
}
/** A call to `permit` that fully specifies the permitted parameters. */
private class PermitCallSanitizer extends Sanitizer, DataFlow::CallNode {
PermitCallSanitizer() {
this.getMethodName() = "permit" and
not hasEmptyHash(this.getArgument(_).asExpr().getExpr())
}
}
/** A call to `permit` that uses an empty hash, which allows arbitrary keys to be specified. */
private class PermitCallMassPermit extends MassPermit instanceof DataFlow::CallNode {
PermitCallMassPermit() {
this.(DataFlow::CallNode).getMethodName() = "permit" and
hasEmptyHash(this.(DataFlow::CallNode).getArgument(_).asExpr().getExpr())
}
override DataFlow::Node getParamsArgument() { result = this.(DataFlow::CallNode).getReceiver() }
override DataFlow::Node getPermittedParamsResult() { result = this }
}
/** A call to `to_unsafe_h`, which allows arbitrary parameter. */
private class ToUnsafeHashCall extends MassPermit instanceof DataFlow::CallNode {
ToUnsafeHashCall() { this.(DataFlow::CallNode).getMethodName() = "to_unsafe_h" }
override DataFlow::Node getParamsArgument() { result = this.(DataFlow::CallNode).getReceiver() }
override DataFlow::Node getPermittedParamsResult() { result = this }
}
}

View File

@@ -1,10 +1,4 @@
edges
| test.rb:23:25:23:37 | call to [] [element 0] | test.rb:23:25:23:37 | call to [] | provenance | |
| test.rb:23:26:23:36 | call to user_params | test.rb:23:25:23:37 | call to [] [element 0] | provenance | |
| test.rb:24:26:24:38 | call to [] [element 0] | test.rb:24:26:24:38 | call to [] | provenance | |
| test.rb:24:27:24:37 | call to user_params | test.rb:24:26:24:38 | call to [] [element 0] | provenance | |
| test.rb:30:21:30:33 | call to [] [element 0] | test.rb:30:21:30:33 | call to [] | provenance | |
| test.rb:30:22:30:32 | call to user_params | test.rb:30:21:30:33 | call to [] [element 0] | provenance | |
| test.rb:43:9:43:14 | call to params | test.rb:43:9:43:29 | call to require | provenance | |
| test.rb:43:9:43:29 | call to require | test.rb:43:9:43:37 | call to permit! | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:8:18:8:28 | call to user_params | provenance | |
@@ -13,20 +7,25 @@ edges
| test.rb:43:9:43:37 | call to permit! | test.rb:20:22:20:32 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:21:21:21:31 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:22:22:22:32 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:23:26:23:36 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:24:27:24:37 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:25:21:25:31 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:26:24:26:34 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:27:22:27:32 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:28:25:28:35 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:29:21:29:31 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:30:22:30:32 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:31:32:31:42 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:32:33:32:43 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:33:36:33:46 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:34:32:34:42 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:35:33:35:43 | call to user_params | provenance | |
| test.rb:43:9:43:37 | call to permit! | test.rb:36:26:36:36 | call to user_params | provenance | |
| test.rb:47:9:47:9 | x | test.rb:48:9:48:9 | x | provenance | |
| test.rb:47:13:47:18 | call to params | test.rb:47:13:47:25 | ...[...] | provenance | |
| test.rb:47:13:47:25 | ...[...] | test.rb:47:9:47:9 | x | provenance | |
| test.rb:48:9:48:9 | [post] x | test.rb:49:18:49:18 | x | provenance | |
| test.rb:48:9:48:9 | x | test.rb:48:9:48:9 | [post] x | provenance | |
| test.rb:51:18:51:23 | call to params | test.rb:51:18:51:40 | call to permit | provenance | |
| test.rb:52:18:52:23 | call to params | test.rb:52:18:52:69 | call to permit | provenance | |
| test.rb:53:18:53:23 | call to params | test.rb:53:18:53:35 | call to to_unsafe_h | provenance | |
nodes
| test.rb:8:18:8:28 | call to user_params | semmle.label | call to user_params |
| test.rb:18:20:18:30 | call to user_params | semmle.label | call to user_params |
@@ -34,20 +33,11 @@ nodes
| test.rb:20:22:20:32 | call to user_params | semmle.label | call to user_params |
| test.rb:21:21:21:31 | call to user_params | semmle.label | call to user_params |
| test.rb:22:22:22:32 | call to user_params | semmle.label | call to user_params |
| test.rb:23:25:23:37 | call to [] | semmle.label | call to [] |
| test.rb:23:25:23:37 | call to [] [element 0] | semmle.label | call to [] [element 0] |
| test.rb:23:26:23:36 | call to user_params | semmle.label | call to user_params |
| test.rb:24:26:24:38 | call to [] | semmle.label | call to [] |
| test.rb:24:26:24:38 | call to [] [element 0] | semmle.label | call to [] [element 0] |
| test.rb:24:27:24:37 | call to user_params | semmle.label | call to user_params |
| test.rb:25:21:25:31 | call to user_params | semmle.label | call to user_params |
| test.rb:26:24:26:34 | call to user_params | semmle.label | call to user_params |
| test.rb:27:22:27:32 | call to user_params | semmle.label | call to user_params |
| test.rb:28:25:28:35 | call to user_params | semmle.label | call to user_params |
| test.rb:29:21:29:31 | call to user_params | semmle.label | call to user_params |
| test.rb:30:21:30:33 | call to [] | semmle.label | call to [] |
| test.rb:30:21:30:33 | call to [] [element 0] | semmle.label | call to [] [element 0] |
| test.rb:30:22:30:32 | call to user_params | semmle.label | call to user_params |
| test.rb:31:32:31:42 | call to user_params | semmle.label | call to user_params |
| test.rb:32:33:32:43 | call to user_params | semmle.label | call to user_params |
| test.rb:33:36:33:46 | call to user_params | semmle.label | call to user_params |
@@ -57,6 +47,18 @@ nodes
| test.rb:43:9:43:14 | call to params | semmle.label | call to params |
| test.rb:43:9:43:29 | call to require | semmle.label | call to require |
| test.rb:43:9:43:37 | call to permit! | semmle.label | call to permit! |
| test.rb:47:9:47:9 | x | semmle.label | x |
| test.rb:47:13:47:18 | call to params | semmle.label | call to params |
| test.rb:47:13:47:25 | ...[...] | semmle.label | ...[...] |
| test.rb:48:9:48:9 | [post] x | semmle.label | [post] x |
| test.rb:48:9:48:9 | x | semmle.label | x |
| test.rb:49:18:49:18 | x | semmle.label | x |
| test.rb:51:18:51:23 | call to params | semmle.label | call to params |
| test.rb:51:18:51:40 | call to permit | semmle.label | call to permit |
| test.rb:52:18:52:23 | call to params | semmle.label | call to params |
| test.rb:52:18:52:69 | call to permit | semmle.label | call to permit |
| test.rb:53:18:53:23 | call to params | semmle.label | call to params |
| test.rb:53:18:53:35 | call to to_unsafe_h | semmle.label | call to to_unsafe_h |
subpaths
#select
| test.rb:8:18:8:28 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:8:18:8:28 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
@@ -65,17 +67,18 @@ subpaths
| test.rb:20:22:20:32 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:20:22:20:32 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:21:21:21:31 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:21:21:21:31 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:22:22:22:32 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:22:22:22:32 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:23:25:23:37 | call to [] | test.rb:43:9:43:14 | call to params | test.rb:23:25:23:37 | call to [] | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:24:26:24:38 | call to [] | test.rb:43:9:43:14 | call to params | test.rb:24:26:24:38 | call to [] | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:25:21:25:31 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:25:21:25:31 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:26:24:26:34 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:26:24:26:34 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:27:22:27:32 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:27:22:27:32 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:28:25:28:35 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:28:25:28:35 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:29:21:29:31 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:29:21:29:31 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:30:21:30:33 | call to [] | test.rb:43:9:43:14 | call to params | test.rb:30:21:30:33 | call to [] | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:31:32:31:42 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:31:32:31:42 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:32:33:32:43 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:32:33:32:43 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:33:36:33:46 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:33:36:33:46 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:34:32:34:42 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:34:32:34:42 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:35:33:35:43 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:35:33:35:43 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:36:26:36:36 | call to user_params | test.rb:43:9:43:14 | call to params | test.rb:36:26:36:36 | call to user_params | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:43:9:43:14 | call to params | this remote flow source |
| test.rb:49:18:49:18 | x | test.rb:47:13:47:18 | call to params | test.rb:49:18:49:18 | x | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:47:13:47:18 | call to params | this remote flow source |
| test.rb:51:18:51:40 | call to permit | test.rb:51:18:51:23 | call to params | test.rb:51:18:51:40 | call to permit | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:51:18:51:23 | call to params | this remote flow source |
| test.rb:52:18:52:69 | call to permit | test.rb:52:18:52:23 | call to params | test.rb:52:18:52:69 | call to permit | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:52:18:52:23 | call to params | this remote flow source |
| test.rb:53:18:53:35 | call to to_unsafe_h | test.rb:53:18:53:23 | call to params | test.rb:53:18:53:35 | call to to_unsafe_h | This mass assignment operation can assign user-controlled attributes from $@. | test.rb:53:18:53:23 | call to params | this remote flow source |

View File

@@ -42,4 +42,15 @@ class UserController < ActionController::Base
def user_params
params.require(:user).permit!
end
def create4
x = params[:user]
x.permit!
User.new(x) # BAD
User.new(x.permit(:name,:address)) # GOOD
User.new(params.permit(user: {})) # BAD
User.new(params.permit(user: [:name, :address, {friends:{}}])) # BAD
User.new(params.to_unsafe_h) # BAD
User.new(params.permit(user: [:name, :address]).to_unsafe_h) # GOOD
end
end