From 94d41b9fa4be0bd79c012bf74635a1fcf6ceb8a0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 3 Oct 2022 09:52:35 +0200 Subject: [PATCH] Ruby: add hook for adding type-tracking steps fixup docs fixup docs fixup TypeTrackingStep --- .../ruby/typetracking/TypeTrackerSpecific.qll | 113 +++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll index b5e28985683..fdd6b6be853 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll @@ -106,7 +106,11 @@ private predicate summarizedLocalStep(Node nodeFrom, Node nodeTo) { } /** Holds if there is a level step from `nodeFrom` to `nodeTo`. */ -predicate levelStep(Node nodeFrom, Node nodeTo) { summarizedLocalStep(nodeFrom, nodeTo) } +predicate levelStep(Node nodeFrom, Node nodeTo) { + summarizedLocalStep(nodeFrom, nodeTo) + or + TypeTrackingStep::step(nodeFrom, nodeTo) +} pragma[noinline] private predicate argumentPositionMatch( @@ -235,6 +239,8 @@ predicate basicStoreStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet conten not exists(pair.getKey().getConstantValue()) and contents.isAnyElement() ) + or + TypeTrackingStep::storeStep(nodeFrom, nodeTo, contents) } private predicate hashLiteralStore(DataFlow::CallNode hashCreation, DataFlow::Node argument) { @@ -280,6 +286,8 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet content nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) ) + or + TypeTrackingStep::loadStep(nodeFrom, nodeTo, contents) } /** @@ -298,6 +306,8 @@ predicate basicLoadStoreStep( nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) ) + or + TypeTrackingStep::loadStoreStep(nodeFrom, nodeTo, loadContent, storeContent) } /** @@ -314,6 +324,8 @@ predicate basicWithoutContentStep(Node nodeFrom, Node nodeTo, ContentFilter filt nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) ) + or + TypeTrackingStep::withoutContentStep(nodeFrom, nodeTo, filter) } /** @@ -338,6 +350,8 @@ predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter) nodeFrom.asExpr() = node.asExpr().(Cfg::CfgNodes::ExprNodes::UnaryOperationCfgNode).getOperand() and filter = MkElementFilter() ) + or + TypeTrackingStep::withContentStep(nodeFrom, nodeTo, filter) } /** @@ -562,3 +576,100 @@ private DataFlow::Node evaluateSummaryComponentStackLocal( ) ) } + +private newtype TUnit = MkUnit() + +/** + * A data flow edge that should be followed by type tracking. + * + * This type of edge does not affect the local data flow graph, and is not used by data-flow configurations. + * + * Note: For performance reasons, all subclasses of this class should be part + * of the standard library, and their implementations may not depend on API graphs. + * For query-specific steps, consider including the custom steps in the type-tracking predicate itself. + */ +class TypeTrackingStep extends TUnit { + /** Gets the string `"unit"`. */ + string toString() { result = "unit" } + + /** + * Holds if type-tracking should step from `pred` to `succ`. + */ + predicate step(Node pred, Node succ) { none() } + + /** + * Holds if type-tracking should step from `pred` into the `content` of `succ`. + */ + predicate storeStep(Node pred, TypeTrackingNode succ, TypeTrackerContent content) { none() } + + /** + * Holds if type-tracking should step from the `content` of `pred` to `succ`. + */ + predicate loadStep(Node pred, Node succ, TypeTrackerContent content) { none() } + + /** + * Holds if type-tracking should step from the `loadContent` of `pred` to the `storeContent` in `succ`. + */ + predicate loadStoreStep( + Node pred, TypeTrackingNode succ, TypeTrackerContent loadContent, + TypeTrackerContent storeContent + ) { + none() + } + + /** + * Holds if type-tracking should step from `pred` to `succ` but block flow of contents matched by `filter` through here. + */ + predicate withoutContentStep(Node pred, Node succ, ContentFilter filter) { none() } + + /** + * Holds if type-tracking should step from `pred` to `succ` if inside a content matched by `filter`. + */ + predicate withContentStep(Node pred, Node succ, ContentFilter filter) { none() } +} + +/** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */ +module TypeTrackingStep { + /** + * Holds if type-tracking should step from `pred` to `succ`. + */ + predicate step(Node pred, Node succ) { any(TypeTrackingStep st).step(pred, succ) } + + /** + * Holds if type-tracking should step from `pred` into the `content` of `succ`. + */ + predicate storeStep(Node pred, TypeTrackingNode succ, TypeTrackerContent content) { + any(TypeTrackingStep st).storeStep(pred, succ, content) + } + + /** + * Holds if type-tracking should step from the `content` of `pred` to `succ`. + */ + predicate loadStep(Node pred, Node succ, TypeTrackerContent content) { + any(TypeTrackingStep st).loadStep(pred, succ, content) + } + + /** + * Holds if type-tracking should step from the `loadContent` of `pred` to the `storeContent` in `succ`. + */ + predicate loadStoreStep( + Node pred, TypeTrackingNode succ, TypeTrackerContent loadContent, + TypeTrackerContent storeContent + ) { + any(TypeTrackingStep st).loadStoreStep(pred, succ, loadContent, storeContent) + } + + /** + * Holds if type-tracking should step from `pred` to `succ` but block flow of contents matched by `filter` through here. + */ + predicate withoutContentStep(Node pred, Node succ, ContentFilter filter) { + any(TypeTrackingStep st).withoutContentStep(pred, succ, filter) + } + + /** + * Holds if type-tracking should step from `pred` to `succ` if inside a content matched by `filter`. + */ + predicate withContentStep(Node pred, Node succ, ContentFilter filter) { + any(TypeTrackingStep st).withContentStep(pred, succ, filter) + } +}