mirror of
https://github.com/github/codeql.git
synced 2026-04-26 09:15:12 +02:00
JS: Port String#replace to flow summary
This commit is contained in:
@@ -409,18 +409,27 @@ module TaintTracking {
|
||||
]).getACall() and
|
||||
pred = c.getArgument(0)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint propagating edge for the string `replace` function.
|
||||
*
|
||||
* This is a legacy step as it crosses a function boundary, and would thus be converted to a jump step.
|
||||
*/
|
||||
private class ReplaceCallbackSteps extends LegacyTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
// In and out of .replace callbacks
|
||||
exists(StringReplaceCall call |
|
||||
// Into the callback if the regexp does not sanitize matches
|
||||
hasWildcardReplaceRegExp(call) and
|
||||
pred = call.getReceiver() and
|
||||
succ = call.getReplacementCallback().getParameter(0)
|
||||
or
|
||||
// In and out of .replace callbacks
|
||||
exists(StringReplaceCall call |
|
||||
// Into the callback if the regexp does not sanitize matches
|
||||
hasWildcardReplaceRegExp(call) and
|
||||
pred = call.getReceiver() and
|
||||
succ = call.getReplacementCallback().getParameter(0)
|
||||
or
|
||||
// Out of the callback
|
||||
pred = call.getReplacementCallback().getReturnNode() and
|
||||
succ = call
|
||||
)
|
||||
// Out of the callback
|
||||
pred = call.getReplacementCallback().getReturnNode() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,3 +4,4 @@ private import AsyncAwait
|
||||
private import Maps2
|
||||
private import Promises2
|
||||
private import Sets2
|
||||
private import Strings2
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Contains flow summaries and steps modelling flow through string methods.
|
||||
*/
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
|
||||
/** Holds if the given call takes a regexp containing a wildcard. */
|
||||
pragma[noinline]
|
||||
private predicate hasWildcardReplaceRegExp(StringReplaceCall call) {
|
||||
RegExp::isWildcardLike(call.getRegExp().getRoot().getAChild*())
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary for calls to `.replace` or `.replaceAll` (without a regexp pattern containing a wildcard).
|
||||
*/
|
||||
private class StringReplaceNoWildcard extends SummarizedCallable {
|
||||
StringReplaceNoWildcard() {
|
||||
this = "String#replace / String#replaceAll (without wildcard pattern)"
|
||||
}
|
||||
|
||||
override StringReplaceCall getACall() { not hasWildcardReplaceRegExp(result) }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = false and
|
||||
(
|
||||
input = "Argument[this]" and
|
||||
output = "ReturnValue"
|
||||
or
|
||||
input = "Argument[1].ReturnValue" and
|
||||
output = "ReturnValue"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary for calls to `.replace` or `.replaceAll` (with a regexp pattern containing a wildcard).
|
||||
*
|
||||
* In this case, the receiver is considered to flow into the callback.
|
||||
*/
|
||||
private class StringReplaceWithWildcard extends SummarizedCallable {
|
||||
StringReplaceWithWildcard() {
|
||||
this = "String#replace / String#replaceAll (with wildcard pattern)"
|
||||
}
|
||||
|
||||
override StringReplaceCall getACall() { hasWildcardReplaceRegExp(result) }
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = false and
|
||||
(
|
||||
input = "Argument[this]" and
|
||||
output = ["ReturnValue", "Argument[1].Parameter[0]"]
|
||||
or
|
||||
input = "Argument[1].ReturnValue" and
|
||||
output = "ReturnValue"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class StringSplit extends SummarizedCallable {
|
||||
StringSplit() { this = "String#split" }
|
||||
|
||||
override DataFlow::MethodCallNode getACallSimple() {
|
||||
result.getMethodName() = "split" and result.getNumArgument() = 1
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
preservesValue = false and
|
||||
input = "Argument[this]" and
|
||||
output = "ReturnValue.ArrayElement"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user