mirror of
https://github.com/github/codeql.git
synced 2026-03-01 05:13:41 +01:00
Merge pull request #4358 from joefarebrother/format-taint
Java: Add taint steps through string formatting methods
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user