Ruby: Allow for implicit array reads at all sinks during taint tracking

This commit is contained in:
Tom Hvitved
2023-03-27 13:42:11 +02:00
parent 111227e763
commit e258324960
23 changed files with 1452 additions and 1396 deletions

View File

@@ -17,7 +17,10 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
* of `c` at sinks and inputs to additional taint steps.
*/
bindingset[node]
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() }
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) {
exists(node) and
c.isElementOfTypeOrUnknown("int")
}
private CfgNodes::ExprNodes::VariableWriteAccessCfgNode variablesInPattern(
CfgNodes::ExprNodes::CasePatternCfgNode p

View File

@@ -201,11 +201,8 @@ private predicate sqlFragmentArgumentInner(DataFlow::CallNode call, DataFlow::No
}
private predicate sqlFragmentArgument(DataFlow::CallNode call, DataFlow::Node sink) {
exists(DataFlow::Node arg |
sqlFragmentArgumentInner(call, arg) and
sink = [arg, arg.(DataFlow::ArrayLiteralNode).getElement(0)] and
unsafeSqlExpr(sink.asExpr().getExpr())
)
sqlFragmentArgumentInner(call, sink) and
unsafeSqlExpr(sink.asExpr().getExpr())
}
// An expression that, if tainted by unsanitized input, should not be used as

View File

@@ -210,9 +210,28 @@ module Array {
}
}
private predicate isKnownRange(RangeLiteral rl, int start, int end) {
(
// Either an explicit, positive beginning index...
start = rl.getBegin().getConstantValue().getInt() and start >= 0
or
// Or a begin-less one, since `..n` is equivalent to `0..n`
not exists(rl.getBegin()) and start = 0
) and
// There must be an explicit end. An end-less range like `2..` is not
// treated as a known range, since we don't track the length of the array.
exists(int e | e = rl.getEnd().getConstantValue().getInt() and e >= 0 |
rl.isInclusive() and end = e
or
rl.isExclusive() and end = e - 1
)
}
/**
* A call to `[]` with an unknown argument, which could be either an index or
* a range.
* a range. To avoid spurious flow, we are going to ignore the possibility
* that the argument might be a range (unless it is an explicit range literal,
* see `ElementReferenceRangeReadUnknownSummary`).
*/
private class ElementReferenceReadUnknownSummary extends ElementReferenceReadSummary {
ElementReferenceReadUnknownSummary() {
@@ -223,7 +242,7 @@ module Array {
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = ["ReturnValue", "ReturnValue.Element[?]"] and
output = "ReturnValue" and
preservesValue = true
}
}
@@ -242,24 +261,8 @@ module Array {
)
or
mc.getNumberOfArguments() = 1 and
exists(RangeLiteral rl |
rl = mc.getArgument(0) and
(
// Either an explicit, positive beginning index...
start = rl.getBegin().getConstantValue().getInt() and start >= 0
or
// Or a begin-less one, since `..n` is equivalent to `0..n`
not exists(rl.getBegin()) and start = 0
) and
// There must be an explicit end. An end-less range like `2..` is not
// treated as a known range, since we don't track the length of the array.
exists(int e | e = rl.getEnd().getConstantValue().getInt() and e >= 0 |
rl.isInclusive() and end = e
or
rl.isExclusive() and end = e - 1
) and
this = methodName + "(" + start + ".." + end + ")"
)
isKnownRange(mc.getArgument(0), start, end) and
this = methodName + "(" + start + ".." + end + ")"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
@@ -291,12 +294,7 @@ module Array {
)
or
mc.getNumberOfArguments() = 1 and
exists(RangeLiteral rl | rl = mc.getArgument(0) |
exists(rl.getBegin()) and
not exists(int b | b = rl.getBegin().getConstantValue().getInt() and b >= 0)
or
not exists(int e | e = rl.getEnd().getConstantValue().getInt() and e >= 0)
)
mc.getArgument(0) = any(RangeLiteral range | not isKnownRange(range, _, _))
)
}

View File

@@ -32,12 +32,6 @@ deprecated class Configuration extends TaintTracking::Configuration {
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureHasSourceCallContext
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet set) {
// allow implicit reads of array elements
this.isSink(node) and
set.isElementOfTypeOrUnknown("int")
}
}
private module UnsafeCodeConstructionConfig implements DataFlow::ConfigSig {

View File

@@ -34,12 +34,6 @@ deprecated class Configuration extends TaintTracking::Configuration {
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureHasSourceCallContext
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet set) {
// allow implicit reads of array elements
this.isSink(node) and
set.isElementOfTypeOrUnknown("int")
}
}
private module UnsafeShellCommandConstructionConfig implements DataFlow::ConfigSig {