diff --git a/java/ql/src/semmle/code/java/dataflow/TaintTrackingFrameworks.qll b/java/ql/src/semmle/code/java/dataflow/TaintTrackingFrameworks.qll new file mode 100644 index 00000000000..26463c33d1e --- /dev/null +++ b/java/ql/src/semmle/code/java/dataflow/TaintTrackingFrameworks.qll @@ -0,0 +1,12 @@ +/** + * Provides taint tracking information for frameworks. + * When a new framework is added that provides taint tracking steps, it should be imported here. + */ + +import semmle.code.java.frameworks.jackson.JacksonSerializability +import semmle.code.java.frameworks.android.Intent +import semmle.code.java.frameworks.android.SQLite +import semmle.code.java.frameworks.Guice +import semmle.code.java.frameworks.Protobuf +import semmle.code.java.frameworks.spring.SpringController +import semmle.code.java.frameworks.spring.SpringHttp diff --git a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index 8818dc37b1a..833e849680f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -5,15 +5,9 @@ private import semmle.code.java.dataflow.SSA private import semmle.code.java.dataflow.DefUse private import semmle.code.java.security.SecurityTests private import semmle.code.java.security.Validation -private import semmle.code.java.frameworks.android.Intent -private import semmle.code.java.frameworks.android.SQLite -private import semmle.code.java.frameworks.Guice -private import semmle.code.java.frameworks.Protobuf -private import semmle.code.java.frameworks.spring.SpringController -private import semmle.code.java.frameworks.spring.SpringHttp private import semmle.code.java.Maps private import semmle.code.java.dataflow.internal.ContainerFlow -private import semmle.code.java.frameworks.jackson.JacksonSerializability +private import semmle.code.java.dataflow.TaintTrackingFrameworks /** * Holds if taint can flow from `src` to `sink` in zero or more @@ -78,6 +72,34 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) { any(AdditionalTaintStep a).step(src, sink) } +/** + * A method that returns tainted data when one of its inputs (an argument or the qualifier) are tainted. + * + * Extend this class to add additional taint steps through a method that should + * apply to all taint configurations. + */ +abstract class TaintPreservingMethod extends Method { + /** + * Holds if this method returns tainted data when `arg` tainted. + * `arg` is a parameter index, or is -1 to indicate the qualifier. + */ + abstract predicate returnsTaint(int arg); +} + +/** + * A method that transfers taint from one of its inputs (an argument or the qualifier) to another. + * + * Extend this class to add additional taint steps through a method that should + * apply to all taint configurations. + */ +abstract class TaintTransferringMethod extends Method { + /** + * Holds if this method 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() } +} + /** * Holds if `node` should be a sanitizer in all global taint flow configurations * but not in local taint. @@ -300,6 +322,8 @@ private predicate taintPreservingQualifierToArgument(Method m, int arg) { m.getDeclaringType().getASupertype*().hasQualifiedName("java.io", "Reader") and m.hasName("read") and arg = 0 + or + m.(TaintTransferringMethod).transfersTaint(-1, arg) } /** Access to a method that passes taint from the qualifier. */ @@ -412,6 +436,8 @@ private predicate taintPreservingQualifierToMethod(Method m) { // buildUnionSubQuery(String typeDiscriminatorColumn, String[] unionColumns, Set columnsPresentInTable, int computedColumnsOffset, String typeDiscriminatorValue, String selection, String[] selectionArgs, String groupBy, String having) // buildUnionSubQuery(String typeDiscriminatorColumn, String[] unionColumns, Set columnsPresentInTable, int computedColumnsOffset, String typeDiscriminatorValue, String selection, String groupBy, String having) m.hasName(["buildQuery", "buildUnionQuery", "buildUnionSubQuery"]) + or + m.(TaintPreservingMethod).returnsTaint(-1) } private class StringReplaceMethod extends Method { @@ -429,7 +455,7 @@ private predicate unsafeEscape(MethodAccess ma) { // Removing `