Files
codeql/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll
2022-12-05 09:49:38 +01:00

141 lines
5.2 KiB
Plaintext

/**
* Provides classes representing various flow steps for taint tracking.
*/
private import java
private import semmle.code.java.dataflow.DataFlow
/**
* A module importing the frameworks that implement additional flow steps,
* ensuring that they are visible to the taint tracking library.
*/
private module Frameworks {
private import semmle.code.java.frameworks.android.AsyncTask
private import semmle.code.java.frameworks.android.Intent
private import semmle.code.java.frameworks.android.Slice
private import semmle.code.java.frameworks.android.SQLite
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.frameworks.ApacheHttp
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.frameworks.Guice
private import semmle.code.java.frameworks.jackson.JacksonSerializability
private import semmle.code.java.frameworks.Properties
private import semmle.code.java.frameworks.Protobuf
private import semmle.code.java.frameworks.ratpack.RatpackExec
private import semmle.code.java.JDK
}
/**
* A method that returns the exact value of one of its parameters or the qualifier.
*
* Extend this class and override `returnsValue` to add additional value-preserving steps through a
* method that should be added to the basic local flow step relation.
*
* These steps will be visible for all global data-flow purposes, as well as via
* `DataFlow::Node.getASuccessor` and other related functions exposing intraprocedural dataflow.
*/
abstract class ValuePreservingMethod extends Method {
/**
* Holds if this method returns precisely the value passed into argument `arg`.
* `arg` is a parameter index, or is -1 to indicate the qualifier.
*/
abstract predicate returnsValue(int arg);
}
/**
* A method that returns the exact value of its qualifier (e.g., `return this;`)
*
* Extend this class to add additional value-preserving steps from qualifier to return value through a
* method that should be added to the basic local flow step relation.
*
* These steps will be visible for all global data-flow purposes, as well as via
* `DataFlow::Node.getASuccessor` and other related functions exposing intraprocedural dataflow.
*/
abstract class FluentMethod extends ValuePreservingMethod {
override predicate returnsValue(int arg) { arg = -1 }
}
/**
* A unit class for adding additional taint steps.
*
* Extend this class to add additional taint steps that should apply to all
* taint configurations.
*/
class AdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for all configurations.
*/
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
}
/**
* A unit class for adding additional value steps.
*
* Extend this class to add additional value-preserving steps that should apply
* to all data flow configurations.
*/
class AdditionalValueStep extends Unit {
/**
* Holds if the step from `node1` to `node2` is a value-preserving step and
* should apply to all data flow configurations.
*/
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
}
/**
* 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 TaintPreservingCallable extends Callable {
/**
* 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 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 NumberTaintPreservingCallable extends TaintPreservingCallable {
int argument;
NumberTaintPreservingCallable() {
this.getDeclaringType().getAnAncestor().hasQualifiedName("java.lang", "Number") and
(
this instanceof Constructor and
argument = 0
or
this.getName().matches(["to%String", "toByteArray", "%Value"]) and
argument = -1
or
this.getName().matches(["parse%", "valueOf%", "to%String", "decode"]) and
argument = 0
)
}
override predicate returnsTaintFrom(int arg) { arg = argument }
}
/**
* A `Content` that should be implicitly regarded as tainted whenever an object with such `Content`
* is itself tainted.
*
* For example, if we had a type `class Container { Contained field; }`, then by default a tainted
* `Container` and a `Container` with a tainted `Contained` stored in its `field` are distinct.
*
* If `any(DataFlow::FieldContent fc | fc.getField().hasQualifiedName("Container", "field"))` was
* included in this type however, then a tainted `Container` would imply that its `field` is also
* tainted (but not vice versa).
*
* Note that `TaintTracking::Configuration` applies this behavior by default to array, collection,
* map-key and map-value content, so that e.g. a tainted `Map` is assumed to have tainted keys and values.
*/
abstract class TaintInheritingContent extends DataFlow::Content { }