add String#% as a printf like call

This commit is contained in:
erik-krogh
2022-10-17 13:51:36 +02:00
parent d4919d04ba
commit f09e3bd3ac
3 changed files with 43 additions and 3 deletions

View File

@@ -2,7 +2,7 @@
* Provides classes for modeling string formatting libraries.
*/
private import codeql.ruby.ast.Call
private import codeql.ruby.AST as Ast
private import codeql.ruby.DataFlow
private import codeql.ruby.ApiGraphs
private import codeql.ruby.frameworks.core.IO
@@ -33,7 +33,7 @@ class KernelPrintfCall extends PrintfStyleCall {
KernelPrintfCall() {
this = API::getTopLevelMember("Kernel").getAMethodCall("printf")
or
this.asExpr().getExpr() instanceof UnknownMethodCall and
this.asExpr().getExpr() instanceof Ast::UnknownMethodCall and
this.getMethodName() = "printf"
}
@@ -60,7 +60,7 @@ class KernelSprintfCall extends PrintfStyleCall {
KernelSprintfCall() {
this = API::getTopLevelMember("Kernel").getAMethodCall("sprintf")
or
this.asExpr().getExpr() instanceof UnknownMethodCall and
this.asExpr().getExpr() instanceof Ast::UnknownMethodCall and
this.getMethodName() = "sprintf"
}
@@ -78,6 +78,28 @@ class IOPrintfCall extends PrintfStyleCall {
override predicate returnsFormatted() { none() }
}
/**
* A call to `String#%`.
*/
class StringPercentCall extends PrintfStyleCall {
StringPercentCall() { this.getMethodName() = "%" }
override DataFlow::Node getFormatString() { result = this.getReceiver() }
override DataFlow::Node getFormatArgument(int n) {
exists(DataFlow::CallNode arrCall |
arrCall = this.getArgument(0) and arrCall.getMethodName() = "[]"
|
n = -2 and // -2 is indicates that the index does not make sense in this context
result = arrCall.getKeywordArgument(_)
or
result = arrCall.getArgument(n)
)
}
override predicate returnsFormatted() { any() }
}
private import codeql.ruby.dataflow.FlowSteps
private import codeql.ruby.CFG

View File

@@ -12,6 +12,10 @@ edges
| tainted_format_string.rb:33:32:33:46 | ...[...] : | tainted_format_string.rb:33:12:33:46 | ... + ... |
| tainted_format_string.rb:36:30:36:35 | call to params : | tainted_format_string.rb:36:30:36:44 | ...[...] : |
| tainted_format_string.rb:36:30:36:44 | ...[...] : | tainted_format_string.rb:36:12:36:46 | "A log message: #{...}" |
| tainted_format_string.rb:39:22:39:27 | call to params : | tainted_format_string.rb:39:22:39:36 | ...[...] : |
| tainted_format_string.rb:39:22:39:36 | ...[...] : | tainted_format_string.rb:39:5:39:45 | "A log message #{...} %{foo}" |
| tainted_format_string.rb:42:22:42:27 | call to params : | tainted_format_string.rb:42:22:42:36 | ...[...] : |
| tainted_format_string.rb:42:22:42:36 | ...[...] : | tainted_format_string.rb:42:5:42:43 | "A log message #{...} %08x" |
nodes
| tainted_format_string.rb:4:12:4:17 | call to params : | semmle.label | call to params : |
| tainted_format_string.rb:4:12:4:26 | ...[...] | semmle.label | ...[...] |
@@ -37,6 +41,12 @@ nodes
| tainted_format_string.rb:36:12:36:46 | "A log message: #{...}" | semmle.label | "A log message: #{...}" |
| tainted_format_string.rb:36:30:36:35 | call to params : | semmle.label | call to params : |
| tainted_format_string.rb:36:30:36:44 | ...[...] : | semmle.label | ...[...] : |
| tainted_format_string.rb:39:5:39:45 | "A log message #{...} %{foo}" | semmle.label | "A log message #{...} %{foo}" |
| tainted_format_string.rb:39:22:39:27 | call to params : | semmle.label | call to params : |
| tainted_format_string.rb:39:22:39:36 | ...[...] : | semmle.label | ...[...] : |
| tainted_format_string.rb:42:5:42:43 | "A log message #{...} %08x" | semmle.label | "A log message #{...} %08x" |
| tainted_format_string.rb:42:22:42:27 | call to params : | semmle.label | call to params : |
| tainted_format_string.rb:42:22:42:36 | ...[...] : | semmle.label | ...[...] : |
subpaths
#select
| tainted_format_string.rb:4:12:4:26 | ...[...] | tainted_format_string.rb:4:12:4:17 | call to params : | tainted_format_string.rb:4:12:4:26 | ...[...] | Format string depends on a $@. | tainted_format_string.rb:4:12:4:17 | call to params | user-provided value |
@@ -50,3 +60,5 @@ subpaths
| tainted_format_string.rb:28:19:28:33 | ...[...] | tainted_format_string.rb:28:19:28:24 | call to params : | tainted_format_string.rb:28:19:28:33 | ...[...] | Format string depends on a $@. | tainted_format_string.rb:28:19:28:24 | call to params | user-provided value |
| tainted_format_string.rb:33:12:33:46 | ... + ... | tainted_format_string.rb:33:32:33:37 | call to params : | tainted_format_string.rb:33:12:33:46 | ... + ... | Format string depends on a $@. | tainted_format_string.rb:33:32:33:37 | call to params | user-provided value |
| tainted_format_string.rb:36:12:36:46 | "A log message: #{...}" | tainted_format_string.rb:36:30:36:35 | call to params : | tainted_format_string.rb:36:12:36:46 | "A log message: #{...}" | Format string depends on a $@. | tainted_format_string.rb:36:30:36:35 | call to params | user-provided value |
| tainted_format_string.rb:39:5:39:45 | "A log message #{...} %{foo}" | tainted_format_string.rb:39:22:39:27 | call to params : | tainted_format_string.rb:39:5:39:45 | "A log message #{...} %{foo}" | Format string depends on a $@. | tainted_format_string.rb:39:22:39:27 | call to params | user-provided value |
| tainted_format_string.rb:42:5:42:43 | "A log message #{...} %08x" | tainted_format_string.rb:42:22:42:27 | call to params : | tainted_format_string.rb:42:5:42:43 | "A log message #{...} %08x" | Format string depends on a $@. | tainted_format_string.rb:42:22:42:27 | call to params | user-provided value |

View File

@@ -34,5 +34,11 @@ class UsersController < ActionController::Base
# Taint via string interpolation
printf("A log message: #{params[:format]}", arg) # BAD
# Using String#
"A log message #{params[:format]} %{foo}" % {foo: "foo"} # BAD
# String# with an array
"A log message #{params[:format]} %08x" % ["foo"] # BAD
end
end