Merge pull request #4358 from joefarebrother/format-taint

Java: Add taint steps through string formatting methods
This commit is contained in:
Anders Schack-Mulligen
2020-10-05 13:25:54 +02:00
committed by GitHub
5 changed files with 162 additions and 0 deletions

View File

@@ -124,6 +124,8 @@ private predicate localAdditionalTaintExprStep(Expr src, Expr sink) {
stringBuilderStep(src, sink)
or
serializationStep(src, sink)
or
formatStep(src, sink)
}
/**
@@ -387,6 +389,9 @@ private predicate taintPreservingQualifierToMethod(Method m) {
stringlist.getTypeArgument(0) instanceof TypeString
)
)
or
m.getDeclaringType() instanceof TypeFormatter and
m.hasName(["format", "out"])
}
private class StringReplaceMethod extends Method {
@@ -447,6 +452,9 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
private predicate taintPreservingArgumentToMethod(Method method) {
method.getDeclaringType() instanceof TypeString and
(method.hasName("format") or method.hasName("formatted") or method.hasName("join"))
or
method.getDeclaringType() instanceof TypeFormatter and
method.hasName("format")
}
/**
@@ -625,6 +633,20 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) {
tracked = ma.getArgument(i) and
sink = ma.getQualifier()
)
or
exists(MethodAccess ma |
taintPreservingArgumentToQualifier(ma.getMethod()) and
tracked = ma.getAnArgument() and
sink = ma.getQualifier()
)
}
/**
* Holds if `method` is a method that transfers taint from any of its arguments to its qualifier.
*/
private predicate taintPreservingArgumentToQualifier(Method method) {
method.getDeclaringType() instanceof TypeFormatter and
method.hasName("format")
}
/**
@@ -722,6 +744,56 @@ class ObjectOutputStreamVar extends LocalVariableDecl {
}
}
/** Flow through string formatting. */
private predicate formatStep(Expr tracked, Expr sink) {
exists(FormatterVar v, VariableAssign def |
def = v.getADef() and
exists(MethodAccess ma, RValue use |
ma.getAnArgument() = tracked and
ma = v.getAFormatMethodAccess() and
use = ma.getQualifier() and
defUsePair(def, use)
) and
exists(RValue output, ClassInstanceExpr cie |
cie = def.getSource() and
output = cie.getArgument(0) and
adjacentUseUse(output, sink) and
exists(RefType t | output.getType().(RefType).getASourceSupertype*() = t |
t.hasQualifiedName("java.io", "OutputStream") or
t.hasQualifiedName("java.lang", "Appendable")
)
)
)
}
/**
* A local variable that is assigned a `Formatter`.
* Writing tainted data to such a formatter causes the underlying
* `OutputStream` or `Appendable` to be tainted.
*/
private class FormatterVar extends LocalVariableDecl {
FormatterVar() {
exists(ClassInstanceExpr cie | cie = this.getAnAssignedValue() |
cie.getType() instanceof TypeFormatter
)
}
VariableAssign getADef() {
result.getSource().(ClassInstanceExpr).getType() instanceof TypeFormatter and
result.getDestVar() = this
}
MethodAccess getAFormatMethodAccess() {
result.getQualifier() = getAnAccess() and
result.getMethod().hasName("format")
}
}
/** The class `java.util.Formatter`. */
private class TypeFormatter extends Class {
TypeFormatter() { this.hasQualifiedName("java.util", "Formatter") }
}
private import StringBuilderVarModule
module StringBuilderVarModule {