Merge pull request #16110 from hvitved/dataflow/param-flow-no-expects-content

Data flow: Block flow at `expectsContents` nodes in `parameterValueFlow`
This commit is contained in:
Tom Hvitved
2024-04-09 11:26:24 +02:00
committed by GitHub
4 changed files with 73 additions and 28 deletions

View File

@@ -0,0 +1,39 @@
private import codeql.ruby.dataflow.FlowSummary
private class ReverseSummary extends SimpleSummarizedCallable {
ReverseSummary() { this = "reverse" }
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].WithElement[any]" and
output = "ReturnValue" and
preservesValue = true
}
}
private module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source
.(DataFlow::PostUpdateNode)
.getPreUpdateNode()
.asExpr()
.getExpr()
.(MethodCall)
.getMethodName() = "reverse"
}
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
mc.getMethodName() = "sink" and
sink.asExpr().getExpr() = mc.getAnArgument()
)
}
}
/**
* This predicate should not have a result. We check that the flow summary for
* `reverse` does not get picked up by the `reverseStepThroughInputOutputAlias`
* logic in `DataFlowImplCommon.qll`.
*/
query predicate noReverseStepThroughInputOutputAlias(DataFlow::Node source, DataFlow::Node sink) {
DataFlow::Global<Config>::flow(source, sink)
}

View File

@@ -0,0 +1,3 @@
x = foo
x.reverse.bar
sink(x)

View File

@@ -863,34 +863,37 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
*/
pragma[nomagic]
private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
p = node and
read = false
or
// local flow
exists(Node mid |
parameterValueFlowCand(p, mid, read) and
simpleLocalFlowStep(mid, node) and
validParameterAliasStep(mid, node)
)
or
// read
exists(Node mid |
parameterValueFlowCand(p, mid, false) and
readSet(mid, _, node) and
read = true
)
or
// flow through: no prior read
exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read)
)
or
// flow through: no read inside method
exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false)
)
(
p = node and
read = false
or
// local flow
exists(Node mid |
parameterValueFlowCand(p, mid, read) and
simpleLocalFlowStep(mid, node) and
validParameterAliasStep(mid, node)
)
or
// read
exists(Node mid |
parameterValueFlowCand(p, mid, false) and
readSet(mid, _, node) and
read = true
)
or
// flow through: no prior read
exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read)
)
or
// flow through: no read inside method
exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false)
)
) and
not expectsContentCached(node, _)
}
pragma[nomagic]