Java: Expand flow step refactoring to Callables

Also add some missing flow steps for StringBuilder
This commit is contained in:
Joe Farebrother
2020-10-12 14:43:21 +01:00
parent 7e2c49fadd
commit eafde05a55
9 changed files with 65 additions and 45 deletions

View File

@@ -32,39 +32,39 @@ class AdditionalTaintStep extends Unit {
}
/**
* A method that preserves taint.
* A method or constructor that preserves taint.
*
* Extend this class and override at least one of `returnsTaintFrom` or `transfersTaint`
* to add additional taint steps through a method that should apply to all taint configurations.
*/
abstract class TaintPreservingMethod extends Method {
abstract class TaintPreservingCallable extends Callable {
/**
* Holds if this method returns tainted data when `arg` tainted.
* Holds if this callable returns tainted data when `arg` tainted.
* `arg` is a parameter index, or is -1 to indicate the qualifier.
*/
predicate returnsTaintFrom(int arg) { none() }
/**
* Holds if this method writes tainted data to `sink` when `src` is tainted.
* Holds if this callable writes tainted data to `sink` when `src` is tainted.
* `src` and `sink` are parameter indices, or -1 to indicate the qualifier.
*/
predicate transfersTaint(int src, int sink) { none() }
}
private class StringTaintPreservingMethod extends TaintPreservingMethod {
StringTaintPreservingMethod() {
private class StringTaintPreservingCallable extends TaintPreservingCallable {
StringTaintPreservingCallable() {
this.getDeclaringType() instanceof TypeString and
this
.hasName(["concat", "copyValueOf", "endsWith", "format", "formatted", "getBytes", "indent",
"intern", "join", "repeat", "split", "strip", "stripIndent", "stripLeading",
"stripTrailing", "substring", "toCharArray", "toLowerCase", "toString", "toUpperCase",
"trim"])
"trim", "String"])
}
override predicate returnsTaintFrom(int arg) {
arg = -1 and not this.isStatic()
or
this.hasName(["concat", "copyValueOf"]) and arg = 0
this.hasName(["concat", "copyValueOf", "String"]) and arg = 0
or
this.hasName(["format", "formatted", "join"]) and arg = [0 .. getNumberOfParameters()]
}

View File

@@ -162,9 +162,6 @@ private predicate inputStreamWrapper(Constructor c, int argi) {
private predicate constructorStep(Expr tracked, ConstructorCall sink) {
exists(int argi | sink.getArgument(argi) = tracked |
exists(string s | sink.getConstructedType().getQualifiedName() = s |
// String constructor does nothing to data
s = "java.lang.String" and argi = 0
or
// some readers preserve the content of streams
s = "java.io.InputStreamReader" and argi = 0
or
@@ -254,6 +251,8 @@ private predicate constructorStep(Expr tracked, ConstructorCall sink) {
argi = 0 and
tracked.getType() instanceof TypeString
)
or
sink.getConstructor().(TaintPreservingCallable).returnsTaintFrom(argToParam(sink, argi))
)
}
@@ -261,11 +260,11 @@ private predicate constructorStep(Expr tracked, ConstructorCall sink) {
* Converts an argument index to a formal parameter index.
* This is relevant for varadic methods.
*/
private int argToParam(MethodAccess ma, int arg) {
exists(ma.getArgument(arg)) and
exists(Method m | m = ma.getMethod() |
if m.isVarargs() and arg >= m.getNumberOfParameters()
then result = m.getNumberOfParameters() - 1
private int argToParam(Call call, int arg) {
exists(call.getArgument(arg)) and
exists(Callable c | c = call.getCallee() |
if c.isVarargs() and arg >= c.getNumberOfParameters()
then result = c.getNumberOfParameters() - 1
else result = arg
)
}
@@ -296,7 +295,7 @@ private predicate taintPreservingQualifierToArgument(Method m, int arg) {
m.hasName("read") and
arg = 0
or
m.(TaintPreservingMethod).transfersTaint(-1, arg)
m.(TaintPreservingCallable).transfersTaint(-1, arg)
}
/** Access to a method that passes taint from the qualifier. */
@@ -378,10 +377,10 @@ private predicate taintPreservingQualifierToMethod(Method m) {
)
)
or
m.(TaintPreservingMethod).returnsTaintFrom(-1)
m.(TaintPreservingCallable).returnsTaintFrom(-1)
}
private class StringReplaceMethod extends TaintPreservingMethod {
private class StringReplaceMethod extends TaintPreservingCallable {
StringReplaceMethod() {
getDeclaringType() instanceof TypeString and
(
@@ -523,7 +522,7 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
method.hasName("append") and
arg = 0
or
method.(TaintPreservingMethod).returnsTaintFrom(arg)
method.(TaintPreservingCallable).returnsTaintFrom(arg)
}
/**
@@ -571,7 +570,7 @@ private predicate taintPreservingArgToArg(Method method, int input, int output)
input = 0 and
output = 2
or
method.(TaintPreservingMethod).transfersTaint(input, output)
method.(TaintPreservingCallable).transfersTaint(input, output)
}
/**
@@ -607,10 +606,14 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) {
method.overrides*(append) and
append.hasName("append") and
arg = 0 and
append.getDeclaringType().hasQualifiedName("java.io", "StringWriter")
(
append.getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") or
append.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer") or
append.getDeclaringType().hasQualifiedName("java.io", "StringWriter")
)
)
or
method.(TaintPreservingMethod).transfersTaint(arg, -1)
method.(TaintPreservingCallable).transfersTaint(arg, -1)
}
/** A comparison or equality test with a constant. */
@@ -734,15 +737,27 @@ private class TypeFormatter extends Class {
TypeFormatter() { this.hasQualifiedName("java.util", "Formatter") }
}
private class FormatterMethod extends TaintPreservingMethod {
FormatterMethod() {
getDeclaringType() instanceof TypeFormatter and
hasName(["format", "out", "toString"])
private class FormatterCallable extends TaintPreservingCallable {
FormatterCallable() {
this.getDeclaringType() instanceof TypeFormatter and
(
this.hasName(["format", "out", "toString"])
or
this
.(Constructor)
.getParameterType(0)
.(RefType)
.getASourceSupertype*()
.hasQualifiedName("java.lang", "Appendable")
)
}
override predicate returnsTaintFrom(int arg) { arg = [-1 .. getNumberOfParameters()] }
override predicate returnsTaintFrom(int arg) {
if this instanceof Constructor then arg = 0 else arg = [-1 .. getNumberOfParameters()]
}
override predicate transfersTaint(int src, int sink) {
this.hasName("format") and
sink = -1 and
src = [0 .. getNumberOfParameters()]
}

View File

@@ -35,7 +35,7 @@ class GuiceProvider extends Interface {
}
}
private class OverridingGetMethod extends TaintPreservingMethod {
private class OverridingGetMethod extends TaintPreservingCallable {
OverridingGetMethod() { this = any(GuiceProvider gp).getAnOverridingGetMethod() }
override predicate returnsTaintFrom(int arg) { arg = -1 }

View File

@@ -56,13 +56,13 @@ class ProtobufMessageLite extends Interface {
}
}
private class TaintPreservingGetterMethod extends TaintPreservingMethod {
private class TaintPreservingGetterMethod extends TaintPreservingCallable {
TaintPreservingGetterMethod() { this = any(ProtobufMessageLite p).getAGetterMethod() }
override predicate returnsTaintFrom(int arg) { arg = -1 }
}
private class TaintPreservingParseFromMethod extends TaintPreservingMethod {
private class TaintPreservingParseFromMethod extends TaintPreservingCallable {
TaintPreservingParseFromMethod() {
exists(ProtobufParser p | this = p.getAParseFromMethod())
or

View File

@@ -34,7 +34,7 @@ class ContextStartActivityMethod extends Method {
}
}
class IntentGetExtraMethod extends Method, TaintPreservingMethod {
class IntentGetExtraMethod extends Method, TaintPreservingCallable {
IntentGetExtraMethod() {
(getName().regexpMatch("get\\w+Extra") or hasName("getExtras")) and
getDeclaringType() instanceof TypeIntent

View File

@@ -228,7 +228,7 @@ private class ContentProviderUpdateMethod extends SQLiteRunner {
override int sqlIndex() { result = 2 }
}
private class QueryBuilderBuildMethod extends TaintPreservingMethod {
private class QueryBuilderBuildMethod extends TaintPreservingCallable {
int argument;
QueryBuilderBuildMethod() {
@@ -255,7 +255,7 @@ private class QueryBuilderBuildMethod extends TaintPreservingMethod {
override predicate returnsTaintFrom(int arg) { argument = arg }
}
private class QueryBuilderAppendMethod extends TaintPreservingMethod {
private class QueryBuilderAppendMethod extends TaintPreservingCallable {
QueryBuilderAppendMethod() {
this.getDeclaringType().getASourceSupertype*() instanceof TypeSQLiteQueryBuilder and
// setProjectionMap(Map<String, String> columnMap)
@@ -273,7 +273,7 @@ private class QueryBuilderAppendMethod extends TaintPreservingMethod {
}
}
private class UnsafeAppendUtilMethod extends TaintPreservingMethod {
private class UnsafeAppendUtilMethod extends TaintPreservingCallable {
UnsafeAppendUtilMethod() {
this.getDeclaringType() instanceof TypeDatabaseUtils and
// String[] appendSelectionArgs(String[] originalValues, String[] newValues)
@@ -284,7 +284,7 @@ private class UnsafeAppendUtilMethod extends TaintPreservingMethod {
override predicate returnsTaintFrom(int arg) { arg = [0 .. getNumberOfParameters()] }
}
private class TaintPreservingQueryMethod extends TaintPreservingMethod {
private class TaintPreservingQueryMethod extends TaintPreservingCallable {
TaintPreservingQueryMethod() {
(
this.getDeclaringType() instanceof AndroidContentProvider or

View File

@@ -28,7 +28,7 @@ abstract class JacksonSerializableType extends Type { }
* A method used for serializing objects using Jackson. The final parameter is the object to be
* serialized.
*/
library class JacksonWriteValueMethod extends TaintPreservingMethod {
library class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
JacksonWriteValueMethod() {
(
getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectWriter") or