From 9c4c35141a1a8f6148b0d16052ca5b919fb5fe73 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 3 Mar 2022 11:11:49 +0100 Subject: [PATCH 1/3] Ruby: Update type tracker test --- .../type-tracker/TypeTracker.expected | 27 +++++++++++++++++++ .../dataflow/type-tracker/TypeTracker.ql | 7 +++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected index 4640f713f074..9f56e87ef112 100644 --- a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected +++ b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected @@ -72,19 +72,29 @@ trackEnd | type_tracker.rb:2:5:5:7 | return return in field= | type_tracker.rb:2:5:5:7 | return return in field= | | type_tracker.rb:2:5:5:7 | return return in field= | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:2:5:5:7 | self (field=) | +| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:9:3:23 | self | +| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:14:3:17 | self | | type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self in field= | +| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:9:3:23 | self | +| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:14:3:17 | self | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:5:5:7 | return return in field= | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | +| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... | +| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... | +| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val | +| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:3:9:3:23 | [post] self | +| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:3:14:3:17 | self | | type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:3:9:3:23 | call to puts | type_tracker.rb:3:9:3:23 | call to puts | | type_tracker.rb:3:9:3:23 | self | type_tracker.rb:3:9:3:23 | self | +| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:3:14:3:17 | self | | type_tracker.rb:3:9:3:23 | self | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:3:14:3:17 | [post] self | type_tracker.rb:3:14:3:17 | [post] self | | type_tracker.rb:3:14:3:17 | self | type_tracker.rb:3:14:3:17 | self | @@ -93,9 +103,11 @@ trackEnd | type_tracker.rb:3:14:3:23 | call to field | type_tracker.rb:3:14:3:23 | call to field | | type_tracker.rb:4:9:4:14 | @field | type_tracker.rb:4:9:4:14 | @field | | type_tracker.rb:4:18:4:20 | val | type_tracker.rb:2:5:5:7 | return return in field= | +| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:9:4:20 | ... = ... | | type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:18:4:20 | val | | type_tracker.rb:4:18:4:20 | val | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:7:5:9:7 | &block | type_tracker.rb:7:5:9:7 | &block | +| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:1:1:10:3 | Container | | type_tracker.rb:7:5:9:7 | field | type_tracker.rb:7:5:9:7 | field | | type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:3:14:3:23 | call to field | | type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:7:5:9:7 | return return in field | @@ -109,20 +121,35 @@ trackEnd | type_tracker.rb:12:1:16:3 | m | type_tracker.rb:12:1:16:3 | m | | type_tracker.rb:12:1:16:3 | return return in m | type_tracker.rb:12:1:16:3 | return return in m | | type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:12:1:16:3 | self (m) | +| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:15:5:15:18 | self | | type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self in m | +| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:15:5:15:18 | self | | type_tracker.rb:13:5:13:7 | var | type_tracker.rb:13:5:13:7 | var | | type_tracker.rb:13:11:13:19 | Container | type_tracker.rb:13:11:13:19 | Container | | type_tracker.rb:13:11:13:19 | [post] Container | type_tracker.rb:13:11:13:19 | [post] Container | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self in field= | +| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:9:3:23 | self | +| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:14:3:17 | self | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:7:5:9:7 | self in field | +| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:13:5:13:23 | ... = ... | +| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:13:5:13:23 | ... = ... | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:13:11:13:23 | call to new | +| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:14:5:14:7 | var | +| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:15:10:15:12 | var | | type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:14:5:14:7 | [post] var | +| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:15:10:15:12 | var | | type_tracker.rb:14:5:14:13 | [post] ... = ... | type_tracker.rb:14:5:14:13 | [post] ... = ... | | type_tracker.rb:14:5:14:13 | __synth__0 | type_tracker.rb:14:5:14:13 | __synth__0 | | type_tracker.rb:14:5:14:13 | call to field= | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:2:16:2:18 | val | +| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:4:9:4:20 | ... = ... | +| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:4:18:4:20 | val | +| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | ... = ... | +| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | ... = ... | +| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | __synth__0 | +| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:23 | ... | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:17:14:23 | "hello" | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:15:5:15:18 | [post] self | type_tracker.rb:15:5:15:18 | [post] self | diff --git a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.ql b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.ql index acd3c516009b..1d568a8e3a16 100644 --- a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.ql +++ b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.ql @@ -13,6 +13,9 @@ query predicate track(LocalSourceNode src, TypeTracker t, LocalSourceNode dst) { exists(TypeTracker t2, LocalSourceNode mid | track(src, t2, mid) and dst = mid.track(t2, t)) } -query predicate trackEnd(LocalSourceNode src, LocalSourceNode dst) { - track(src, TypeTracker::end(), dst) +query predicate trackEnd(LocalSourceNode src, DataFlow::Node dst) { + exists(LocalSourceNode end | + track(src, TypeTracker::end(), end) and + end.flowsTo(dst) + ) } From 95027e746c4a3b0b33be3fd0065f0d80a1d02367 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 1 Mar 2022 17:42:07 +0100 Subject: [PATCH 2/3] Ruby: TypeTracker: add smallstep for functions that return their arguments --- .../ruby/typetracking/TypeTrackerSpecific.qll | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll index e1c83273d822..4c29500ead23 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll @@ -11,12 +11,31 @@ class Node = DataFlowPublic::Node; class TypeTrackingNode = DataFlowPublic::LocalSourceNode; +/** Holds if there is a simple local flow step from `nodeFrom` to `nodeTo` */ predicate simpleLocalFlowStep = DataFlowPrivate::localFlowStepTypeTracker/2; +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ predicate jumpStep = DataFlowPrivate::jumpStep/2; -/** Holds if there is a level step from `pred` to `succ`. */ -predicate levelStep(Node pred, Node succ) { none() } +/** + * Holds if there is a summarized local flow step from `nodeFrom` to `nodeTo`, + * because there is direct flow from a parameter to a return. That is, summarized + * steps are not applied recursively. + */ +pragma[nomagic] +private predicate summarizedLocalStep(Node nodeFrom, Node nodeTo) { + exists(DataFlowPublic::ParameterNode param, DataFlowPrivate::ReturningNode returnNode | + DataFlowPrivate::LocalFlow::getParameterDefNode(param.getParameter()) + .(TypeTrackingNode) + .flowsTo(returnNode) and + callStep(nodeTo.asExpr(), nodeFrom, param) + ) +} + +/** Holds if there is a level step from `nodeFrom` to `nodeTo`. */ +predicate levelStep(Node nodeFrom, Node nodeTo) { summarizedLocalStep(nodeFrom, nodeTo) } /** * Gets the name of a possible piece of content. This will usually include things like @@ -48,6 +67,13 @@ private predicate viableParam( ) } +private predicate callStep(ExprNodes::CallCfgNode call, Node nodeFrom, Node nodeTo) { + exists(DataFlowDispatch::ParameterPosition pos | + argumentPositionMatch(call, nodeFrom, pos) and + viableParam(call, nodeTo, pos) + ) +} + /** * Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call. * @@ -56,10 +82,7 @@ private predicate viableParam( * methods is done using API graphs (which uses type tracking). */ predicate callStep(Node nodeFrom, Node nodeTo) { - exists(ExprNodes::CallCfgNode call, DataFlowDispatch::ParameterPosition pos | - argumentPositionMatch(call, nodeFrom, pos) and - viableParam(call, nodeTo, pos) - ) + callStep(_, nodeFrom, nodeTo) or // In normal data-flow, this will be a local flow step. But for type tracking // we model it as a call step, in order to avoid computing a potential From 200a965fdaf6f8fbacde1f4cbde83ce1c301f44d Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Thu, 3 Mar 2022 14:34:02 +0100 Subject: [PATCH 3/3] Update expected output --- .../library-tests/dataflow/type-tracker/TypeTracker.expected | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected index 9f56e87ef112..c51d2f41b78e 100644 --- a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected +++ b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected @@ -56,6 +56,7 @@ track | type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps with content field | type_tracker.rb:7:5:9:7 | self in field | +| type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:17:14:23 | "hello" | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps with content field | type_tracker.rb:14:5:14:7 | [post] var | @@ -149,6 +150,7 @@ trackEnd | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | ... = ... | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | ... = ... | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | __synth__0 | +| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:23 | ... | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:17:14:23 | "hello" | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:15:10:15:18 | call to field |