Skip to content

Commit 8c31b61

Browse files
Model UploadedFile original_filename and read
1 parent 6dddae0 commit 8c31b61

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import codeql.ruby.controlflow.CfgNodes
88
private import codeql.ruby.DataFlow
99
private import codeql.ruby.dataflow.RemoteFlowSources
1010
private import codeql.ruby.ApiGraphs
11+
private import codeql.ruby.typetracking.TypeTracking
1112
private import codeql.ruby.frameworks.ActionDispatch
1213
private import codeql.ruby.frameworks.ActionView
1314
private import codeql.ruby.frameworks.Rails
@@ -505,6 +506,27 @@ private module ParamsSummaries {
505506
]
506507
}
507508

509+
/** Gets a field of an instance of `ActionController::Parameters` */
510+
private DataFlow::LocalSourceNode paramsField() {
511+
result =
512+
[
513+
paramsInstance(),
514+
paramsInstance().getAMethodCall(methodReturnsTaintFromSelf()).getAnElementRead*()
515+
]
516+
}
517+
518+
private DataFlow::LocalSourceNode paramsFieldType(TypeTracker t) {
519+
t.start() and
520+
result = paramsField()
521+
or
522+
exists(TypeTracker t2 | result = paramsFieldType(t2).track(t2, t))
523+
}
524+
525+
/** Gets a node with a type that can be a field of `ActionController::Parameters */
526+
private DataFlow::LocalSourceNode paramsFieldType() {
527+
paramsFieldType(TypeTracker::end()).flowsTo(result)
528+
}
529+
508530
/**
509531
* A flow summary for methods on `ActionController::Parameters` which
510532
* propagate taint from receiver to return value.
@@ -569,6 +591,44 @@ private module ParamsSummaries {
569591
preservesValue = false
570592
}
571593
}
594+
595+
/** Flow summaries for `ActiveDispatch::Http::UploadedFile`, which can be an field of `ActionController::Parameters`. */
596+
module UploadedFileSummaries {
597+
/** Flow summary for `ActiveDispatch::Http::UploadedFile.original_filename` */
598+
private class UploadedFileOriginalFilenameSummary extends SummarizedCallable {
599+
UploadedFileOriginalFilenameSummary() {
600+
this = "ActionDispatch::Http::UploadedFile::original_filename"
601+
}
602+
603+
override MethodCall getACall() {
604+
result = paramsFieldType().getAMethodCall("original_filename").asExpr().getExpr() and
605+
result.getNumberOfArguments() = 0
606+
}
607+
608+
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
609+
input = "Argument[self]" and output = "ReturnValue" and preservesValue = false
610+
}
611+
}
612+
613+
/**
614+
* Flow summary for `ActiveDispatch::Http::UploadedFile.original_filename`,
615+
* which propagates taint from the receiver to the return value or to the second (buffer) argument
616+
*/
617+
private class UploadedFileReadSummary extends SummarizedCallable {
618+
UploadedFileReadSummary() { this = "ActionDispatch::Http::UploadedFile::read" }
619+
620+
override MethodCall getACall() {
621+
result = paramsFieldType().getAMethodCall("read").asExpr().getExpr() and
622+
result.getNumberOfArguments() in [0 .. 2]
623+
}
624+
625+
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
626+
input = "Argument[self]" and
627+
output = ["ReturnValue", "Argument[1]"] and
628+
preservesValue = false
629+
}
630+
}
631+
}
572632
}
573633

574634
/**

0 commit comments

Comments
 (0)