mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
move model of printf style calls to StringFormatters.qll
This commit is contained in:
@@ -23,3 +23,4 @@ private import codeql.ruby.frameworks.HttpClients
|
||||
private import codeql.ruby.frameworks.XmlParsing
|
||||
private import codeql.ruby.frameworks.ActionDispatch
|
||||
private import codeql.ruby.frameworks.PosixSpawn
|
||||
private import codeql.ruby.frameworks.StringFormatters
|
||||
|
||||
70
ruby/ql/lib/codeql/ruby/frameworks/StringFormatters.qll
Normal file
70
ruby/ql/lib/codeql/ruby/frameworks/StringFormatters.qll
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Provides classes for modeling string formatting libraries.
|
||||
*/
|
||||
|
||||
private import codeql.ruby.ast.Call
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.frameworks.core.IO
|
||||
|
||||
/**
|
||||
* A call to `printf` or `sprintf`.
|
||||
*/
|
||||
abstract class PrintfStyleCall extends DataFlow::CallNode {
|
||||
// We assume that most printf-like calls have the signature f(format_string, args...)
|
||||
/**
|
||||
* Gets the format string of this call.
|
||||
*/
|
||||
DataFlow::Node getFormatString() { result = this.getArgument(0) }
|
||||
|
||||
/**
|
||||
* Gets then `n`th formatted argument of this call.
|
||||
*/
|
||||
DataFlow::Node getFormatArgument(int n) { n >= 0 and result = this.getArgument(n + 1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Kernel.printf`.
|
||||
*/
|
||||
class KernelPrintfCall extends PrintfStyleCall {
|
||||
KernelPrintfCall() {
|
||||
this = API::getTopLevelMember("Kernel").getAMethodCall("printf")
|
||||
or
|
||||
this.asExpr().getExpr() instanceof UnknownMethodCall and
|
||||
this.getMethodName() = "printf"
|
||||
}
|
||||
|
||||
// Kernel#printf supports two signatures:
|
||||
// printf(io, string, ...)
|
||||
// printf(string, ...)
|
||||
override DataFlow::Node getFormatString() {
|
||||
// Because `printf` has two different signatures, we can't be sure which
|
||||
// argument is the format string, so we use a heuristic:
|
||||
// If the first argument has a string value, then we assume it is the format string.
|
||||
// Otherwise we treat both the first and second args as the format string.
|
||||
if this.getArgument(0).getExprNode().getConstantValue().isString(_)
|
||||
then result = this.getArgument(0)
|
||||
else result = this.getArgument([0, 1])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Kernel.sprintf`.
|
||||
*/
|
||||
class KernelSprintfCall extends PrintfStyleCall {
|
||||
KernelSprintfCall() {
|
||||
this = API::getTopLevelMember("Kernel").getAMethodCall("sprintf")
|
||||
or
|
||||
this.asExpr().getExpr() instanceof UnknownMethodCall and
|
||||
this.getMethodName() = "sprintf"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `IO#printf`.
|
||||
*/
|
||||
class IOPrintfCall extends PrintfStyleCall {
|
||||
IOPrintfCall() {
|
||||
this.getReceiver() instanceof IO::IOInstance and this.getMethodName() = "printf"
|
||||
}
|
||||
}
|
||||
@@ -2,82 +2,8 @@
|
||||
* Provides Ruby-specific imports and classes needed for `TaintedFormatStringQuery` and `TaintedFormatStringCustomizations`.
|
||||
*/
|
||||
|
||||
import codeql.ruby.AST
|
||||
import codeql.ruby.frameworks.StringFormatters
|
||||
import codeql.ruby.DataFlow
|
||||
import codeql.ruby.dataflow.RemoteFlowSources
|
||||
import codeql.ruby.ApiGraphs
|
||||
import codeql.ruby.TaintTracking
|
||||
private import codeql.ruby.frameworks.Files
|
||||
private import codeql.ruby.frameworks.core.IO
|
||||
private import codeql.ruby.controlflow.CfgNodes
|
||||
|
||||
/**
|
||||
* A call to `printf` or `sprintf`.
|
||||
*/
|
||||
abstract class PrintfStyleCall extends DataFlow::CallNode {
|
||||
// We assume that most printf-like calls have the signature f(format_string, args...)
|
||||
/**
|
||||
* Gets the format string of this call.
|
||||
*/
|
||||
DataFlow::Node getFormatString() { result = this.getArgument(0) }
|
||||
|
||||
/**
|
||||
* Gets then `n`th formatted argument of this call.
|
||||
*/
|
||||
DataFlow::Node getFormatArgument(int n) { n >= 0 and result = this.getArgument(n + 1) }
|
||||
|
||||
/** Holds if this call returns the formatted string. */
|
||||
predicate returnsFormatted() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Kernel.printf`.
|
||||
*/
|
||||
class KernelPrintfCall extends PrintfStyleCall {
|
||||
KernelPrintfCall() {
|
||||
this = API::getTopLevelMember("Kernel").getAMethodCall("printf")
|
||||
or
|
||||
this.asExpr().getExpr() instanceof UnknownMethodCall and
|
||||
this.getMethodName() = "printf"
|
||||
}
|
||||
|
||||
// Kernel#printf supports two signatures:
|
||||
// printf(io, string, ...)
|
||||
// printf(string, ...)
|
||||
override DataFlow::Node getFormatString() {
|
||||
// Because `printf` has two different signatures, we can't be sure which
|
||||
// argument is the format string, so we use a heuristic:
|
||||
// If the first argument has a string value, then we assume it is the format string.
|
||||
// Otherwise we treat both the first and second args as the format string.
|
||||
if this.getArgument(0).getExprNode().getConstantValue().isString(_)
|
||||
then result = this.getArgument(0)
|
||||
else result = this.getArgument([0, 1])
|
||||
}
|
||||
|
||||
override predicate returnsFormatted() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Kernel.sprintf`.
|
||||
*/
|
||||
class KernelSprintfCall extends PrintfStyleCall {
|
||||
KernelSprintfCall() {
|
||||
this = API::getTopLevelMember("Kernel").getAMethodCall("sprintf")
|
||||
or
|
||||
this.asExpr().getExpr() instanceof UnknownMethodCall and
|
||||
this.getMethodName() = "sprintf"
|
||||
}
|
||||
|
||||
override predicate returnsFormatted() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `IO#printf`.
|
||||
*/
|
||||
class IOPrintfCall extends PrintfStyleCall {
|
||||
IOPrintfCall() {
|
||||
this.getReceiver() instanceof IO::IOInstance and this.getMethodName() = "printf"
|
||||
}
|
||||
|
||||
override predicate returnsFormatted() { none() }
|
||||
}
|
||||
import codeql.ruby.DataFlow
|
||||
|
||||
Reference in New Issue
Block a user