Skip to content

Commit f09e3bd

Browse files
committed
add String#% as a printf like call
1 parent d4919d0 commit f09e3bd

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Provides classes for modeling string formatting libraries.
33
*/
44

5-
private import codeql.ruby.ast.Call
5+
private import codeql.ruby.AST as Ast
66
private import codeql.ruby.DataFlow
77
private import codeql.ruby.ApiGraphs
88
private import codeql.ruby.frameworks.core.IO
@@ -33,7 +33,7 @@ class KernelPrintfCall extends PrintfStyleCall {
3333
KernelPrintfCall() {
3434
this = API::getTopLevelMember("Kernel").getAMethodCall("printf")
3535
or
36-
this.asExpr().getExpr() instanceof UnknownMethodCall and
36+
this.asExpr().getExpr() instanceof Ast::UnknownMethodCall and
3737
this.getMethodName() = "printf"
3838
}
3939

@@ -60,7 +60,7 @@ class KernelSprintfCall extends PrintfStyleCall {
6060
KernelSprintfCall() {
6161
this = API::getTopLevelMember("Kernel").getAMethodCall("sprintf")
6262
or
63-
this.asExpr().getExpr() instanceof UnknownMethodCall and
63+
this.asExpr().getExpr() instanceof Ast::UnknownMethodCall and
6464
this.getMethodName() = "sprintf"
6565
}
6666

@@ -78,6 +78,28 @@ class IOPrintfCall extends PrintfStyleCall {
7878
override predicate returnsFormatted() { none() }
7979
}
8080

81+
/**
82+
* A call to `String#%`.
83+
*/
84+
class StringPercentCall extends PrintfStyleCall {
85+
StringPercentCall() { this.getMethodName() = "%" }
86+
87+
override DataFlow::Node getFormatString() { result = this.getReceiver() }
88+
89+
override DataFlow::Node getFormatArgument(int n) {
90+
exists(DataFlow::CallNode arrCall |
91+
arrCall = this.getArgument(0) and arrCall.getMethodName() = "[]"
92+
|
93+
n = -2 and // -2 is indicates that the index does not make sense in this context
94+
result = arrCall.getKeywordArgument(_)
95+
or
96+
result = arrCall.getArgument(n)
97+
)
98+
}
99+
100+
override predicate returnsFormatted() { any() }
101+
}
102+
81103
private import codeql.ruby.dataflow.FlowSteps
82104
private import codeql.ruby.CFG
83105

ruby/ql/test/query-tests/security/cwe-134/TaintedFormatString.expected

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ edges
1212
| tainted_format_string.rb:33:32:33:46 | ...[...] : | tainted_format_string.rb:33:12:33:46 | ... + ... |
1313
| tainted_format_string.rb:36:30:36:35 | call to params : | tainted_format_string.rb:36:30:36:44 | ...[...] : |
1414
| tainted_format_string.rb:36:30:36:44 | ...[...] : | tainted_format_string.rb:36:12:36:46 | "A log message: #{...}" |
15+
| tainted_format_string.rb:39:22:39:27 | call to params : | tainted_format_string.rb:39:22:39:36 | ...[...] : |
16+
| tainted_format_string.rb:39:22:39:36 | ...[...] : | tainted_format_string.rb:39:5:39:45 | "A log message #{...} %{foo}" |
17+
| tainted_format_string.rb:42:22:42:27 | call to params : | tainted_format_string.rb:42:22:42:36 | ...[...] : |
18+
| tainted_format_string.rb:42:22:42:36 | ...[...] : | tainted_format_string.rb:42:5:42:43 | "A log message #{...} %08x" |
1519
nodes
1620
| tainted_format_string.rb:4:12:4:17 | call to params : | semmle.label | call to params : |
1721
| tainted_format_string.rb:4:12:4:26 | ...[...] | semmle.label | ...[...] |
@@ -37,6 +41,12 @@ nodes
3741
| tainted_format_string.rb:36:12:36:46 | "A log message: #{...}" | semmle.label | "A log message: #{...}" |
3842
| tainted_format_string.rb:36:30:36:35 | call to params : | semmle.label | call to params : |
3943
| tainted_format_string.rb:36:30:36:44 | ...[...] : | semmle.label | ...[...] : |
44+
| tainted_format_string.rb:39:5:39:45 | "A log message #{...} %{foo}" | semmle.label | "A log message #{...} %{foo}" |
45+
| tainted_format_string.rb:39:22:39:27 | call to params : | semmle.label | call to params : |
46+
| tainted_format_string.rb:39:22:39:36 | ...[...] : | semmle.label | ...[...] : |
47+
| tainted_format_string.rb:42:5:42:43 | "A log message #{...} %08x" | semmle.label | "A log message #{...} %08x" |
48+
| tainted_format_string.rb:42:22:42:27 | call to params : | semmle.label | call to params : |
49+
| tainted_format_string.rb:42:22:42:36 | ...[...] : | semmle.label | ...[...] : |
4050
subpaths
4151
#select
4252
| 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
5060
| 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 |
5161
| 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 |
5262
| 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 |
63+
| 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 |
64+
| 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 |

ruby/ql/test/query-tests/security/cwe-134/tainted_format_string.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,11 @@ def show
3434

3535
# Taint via string interpolation
3636
printf("A log message: #{params[:format]}", arg) # BAD
37+
38+
# Using String#
39+
"A log message #{params[:format]} %{foo}" % {foo: "foo"} # BAD
40+
41+
# String# with an array
42+
"A log message #{params[:format]} %08x" % ["foo"] # BAD
3743
end
3844
end

0 commit comments

Comments
 (0)