JS: Do the same for additional taint steps

This commit is contained in:
Asger F
2023-10-10 10:37:57 +02:00
parent 1afe06e3a5
commit 27c7d5004a
2 changed files with 178 additions and 0 deletions

View File

@@ -1,6 +1,28 @@
/**
* Note: The contents of this file are exposed with the `TaintTracking::` prefix, via an import in `TaintTracking.qll`.
*/
private import javascript
private import semmle.javascript.internal.CachedStages
/**
* A taint-propagating data flow edge that should be added to all taint tracking
* configurations, but only those that use the new data flow library.
*
* This class is a singleton, and thus subclasses do not need to specify a characteristic predicate.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Override `Configuration::isAdditionalTaintStep`
* for analysis-specific taint steps.
*/
class AdditionalTaintStep extends Unit {
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge.
*/
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
}
/**
* A taint-propagating data flow edge that should be added to all taint tracking
* configurations in addition to standard data flow edges.
@@ -102,6 +124,106 @@ class SharedTaintStep extends Unit {
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
}
/**
* A taint-propagating data flow edge that should be used with the old data flow library.
*
* This class is a singleton, and thus subclasses do not need to specify a characteristic predicate.
*
* Note: For performance reasons, all subclasses of this class should be part
* of the standard library. Override `Configuration::isAdditionalTaintStep`
* for analysis-specific taint steps.
*
* This class has multiple kinds of `step` predicates; these all have the same
* effect on taint-tracking configurations. However, the categorization of steps
* allows some data-flow configurations to opt in to specific kinds of taint steps.
*/
class LegacyTaintStep extends Unit {
// Each step relation in this class should have a cached version in the `Cached` module
// and be included in the `sharedTaintStep` predicate.
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge.
*/
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through URI manipulation.
*
* Does not include string operations that aren't specific to URIs, such
* as concatenation and substring operations.
*/
predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge contributed by the heuristics library.
*
* Such steps are provided by the `semmle.javascript.heuristics` libraries
* and will default to be being empty if those libraries are not imported.
*/
predicate heuristicStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through persistent storage.
*/
predicate persistentStorageStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through the heap.
*/
predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through arrays.
*
* These steps considers an array to be tainted if it contains tainted elements.
*/
predicate arrayStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through the `state` or `props` or a React component.
*/
predicate viewComponentStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through string concatenation.
*/
predicate stringConcatenationStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through string manipulation (other than concatenation).
*/
predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through data serialization, such as `JSON.stringify`.
*/
predicate serializeStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through data deserialization, such as `JSON.parse`.
*/
predicate deserializeStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
/**
* Holds if `pred` → `succ` should be considered a taint-propagating
* data flow edge through a promise.
*
* These steps consider a promise object to tainted if it can resolve to
* a tainted value.
*/
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
}
/**
* Module existing only to ensure all taint steps are cached as a single stage,
* and without the the `Unit` type column.
@@ -110,6 +232,7 @@ cached
private module Cached {
cached
predicate forceStage() {
// TODO: ensure that this stage is only evaluated if using the old data flow library
Stages::Taint::ref()
}
@@ -120,6 +243,8 @@ private module Cached {
cached
predicate genericStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).step(pred, succ)
or
any(LegacyTaintStep step).step(pred, succ)
}
/**
@@ -129,6 +254,8 @@ private module Cached {
cached
predicate heuristicStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).heuristicStep(pred, succ)
or
any(LegacyTaintStep step).heuristicStep(pred, succ)
}
/**
@@ -143,6 +270,8 @@ private module Cached {
cached
predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).uriStep(pred, succ)
or
any(LegacyTaintStep step).uriStep(pred, succ)
}
/**
@@ -151,6 +280,8 @@ private module Cached {
cached
predicate persistentStorageStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).persistentStorageStep(pred, succ)
or
any(LegacyTaintStep step).persistentStorageStep(pred, succ)
}
/**
@@ -159,6 +290,8 @@ private module Cached {
cached
predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).heapStep(pred, succ)
or
any(LegacyTaintStep step).heapStep(pred, succ)
}
/**
@@ -167,6 +300,8 @@ private module Cached {
cached
predicate arrayStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).arrayStep(pred, succ)
or
any(LegacyTaintStep step).arrayStep(pred, succ)
}
/**
@@ -176,6 +311,8 @@ private module Cached {
cached
predicate viewComponentStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).viewComponentStep(pred, succ)
or
any(LegacyTaintStep step).viewComponentStep(pred, succ)
}
/**
@@ -185,6 +322,8 @@ private module Cached {
cached
predicate stringConcatenationStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).stringConcatenationStep(pred, succ)
or
any(LegacyTaintStep step).stringConcatenationStep(pred, succ)
}
/**
@@ -194,6 +333,8 @@ private module Cached {
cached
predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).stringManipulationStep(pred, succ)
or
any(LegacyTaintStep step).stringManipulationStep(pred, succ)
}
/**
@@ -203,6 +344,8 @@ private module Cached {
cached
predicate serializeStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).serializeStep(pred, succ)
or
any(LegacyTaintStep step).serializeStep(pred, succ)
}
/**
@@ -212,6 +355,8 @@ private module Cached {
cached
predicate deserializeStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).deserializeStep(pred, succ)
or
any(LegacyTaintStep step).deserializeStep(pred, succ)
}
/**
@@ -224,6 +369,8 @@ private module Cached {
cached
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) {
any(SharedTaintStep step).promiseStep(pred, succ)
or
any(LegacyTaintStep step).promiseStep(pred, succ)
}
}
}
@@ -233,6 +380,8 @@ import Cached::Public
/**
* Holds if `pred -> succ` is an edge used by all taint-tracking configurations in
* the old data flow library.
*
* The new data flow library uses a different set of steps, exposed by `AdditionalTaintStep::step`.
*/
predicate sharedTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
Cached::genericStep(pred, succ) or
@@ -248,3 +397,30 @@ predicate sharedTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
deserializeStep(pred, succ) or
promiseStep(pred, succ)
}
/**
* Contains predicates for accessing the taint steps used by taint-tracking configurations
* in the new data flow library.
*/
module AdditionalTaintStep {
/**
* Holds if `pred` → `succ` is considered a taint-propagating data flow edge when
* using the new data flow library.
*/
cached
predicate step(DataFlow::Node pred, DataFlow::Node succ) {
any(AdditionalTaintStep step).step(pred, succ) or
any(SharedTaintStep step).step(pred, succ) or
any(SharedTaintStep step).heuristicStep(pred, succ) or
any(SharedTaintStep step).uriStep(pred, succ) or
any(SharedTaintStep step).persistentStorageStep(pred, succ) or
any(SharedTaintStep step).heapStep(pred, succ) or
any(SharedTaintStep step).arrayStep(pred, succ) or
any(SharedTaintStep step).viewComponentStep(pred, succ) or
any(SharedTaintStep step).stringConcatenationStep(pred, succ) or
any(SharedTaintStep step).stringManipulationStep(pred, succ) or
any(SharedTaintStep step).serializeStep(pred, succ) or
any(SharedTaintStep step).deserializeStep(pred, succ) or
any(SharedTaintStep step).promiseStep(pred, succ)
}
}

View File

@@ -5,6 +5,8 @@ private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as
cached
predicate defaultAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
TaintTracking::AdditionalTaintStep::step(node1, node2)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
node2.(FlowSummaryNode).getSummaryNode(), false)
or