Skip to content

Commit 033df76

Browse files
committed
Ruby: allow fields in flow summaries
1 parent af428a1 commit 033df76

File tree

5 files changed

+38
-1
lines changed

5 files changed

+38
-1
lines changed

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ private import DataFlowDispatch
77
private import SsaImpl as SsaImpl
88
private import FlowSummaryImpl as FlowSummaryImpl
99
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
10+
private import codeql.ruby.frameworks.data.ModelsAsData
1011

1112
/** Gets the callable in which this node occurs. */
1213
DataFlowCallable nodeGetEnclosingCallable(NodeImpl n) { result = n.getEnclosingCallable() }
@@ -353,6 +354,17 @@ private module Cached {
353354
name = any(InstanceVariable v).getName()
354355
or
355356
name = "@" + any(SetterMethodCall c).getTargetName()
357+
or
358+
// The following equation unfortunately leads to a non-monotonic recursion error:
359+
// name = any(AccessPathToken a).getAnArgument("Field")
360+
// Therefore, we use the following instead to extract the field names from the
361+
// external model data. This, unfortunately, does not included any field names used
362+
// in models defined in QL code.
363+
exists(string input, string output |
364+
ModelOutput::relevantSummaryModel(_, _, _, input, output, _)
365+
|
366+
name = [input, output].regexpFind("(?<=(^|\\.)Field\\[)[^\\]]+(?=\\])", _, _).trim()
367+
)
356368
}
357369

358370
/**

ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ SummaryComponent interpretComponentSpecific(AccessPathToken c) {
9898
or
9999
result = interpretElementArg(c.getAnArgument("Element"))
100100
or
101+
result =
102+
FlowSummary::SummaryComponent::content(TSingletonContent(TFieldContent(c.getAnArgument("Field"))))
103+
or
101104
exists(ContentSet cs |
102105
FlowSummary::SummaryComponent::content(cs) = interpretElementArg(c.getAnArgument("WithElement")) and
103106
result = FlowSummary::SummaryComponent::withContent(cs)

ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ edges
8686
| summaries.rb:82:1:82:1 | a [element 2] : | summaries.rb:82:1:82:1 | [post] a [element 2] : |
8787
| summaries.rb:85:6:85:6 | a [element 2] : | summaries.rb:85:6:85:9 | ...[...] |
8888
| summaries.rb:85:6:85:6 | a [element 2] : | summaries.rb:85:6:85:9 | ...[...] |
89+
| summaries.rb:88:1:88:1 | [post] x [@value] : | summaries.rb:89:6:89:6 | x [@value] : |
90+
| summaries.rb:88:1:88:1 | [post] x [@value] : | summaries.rb:89:6:89:6 | x [@value] : |
91+
| summaries.rb:88:13:88:26 | call to source : | summaries.rb:88:1:88:1 | [post] x [@value] : |
92+
| summaries.rb:88:13:88:26 | call to source : | summaries.rb:88:1:88:1 | [post] x [@value] : |
93+
| summaries.rb:89:6:89:6 | x [@value] : | summaries.rb:89:6:89:16 | call to get_value |
94+
| summaries.rb:89:6:89:6 | x [@value] : | summaries.rb:89:6:89:16 | call to get_value |
8995
nodes
9096
| summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : |
9197
| summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : |
@@ -183,6 +189,14 @@ nodes
183189
| summaries.rb:85:6:85:6 | a [element 2] : | semmle.label | a [element 2] : |
184190
| summaries.rb:85:6:85:9 | ...[...] | semmle.label | ...[...] |
185191
| summaries.rb:85:6:85:9 | ...[...] | semmle.label | ...[...] |
192+
| summaries.rb:88:1:88:1 | [post] x [@value] : | semmle.label | [post] x [@value] : |
193+
| summaries.rb:88:1:88:1 | [post] x [@value] : | semmle.label | [post] x [@value] : |
194+
| summaries.rb:88:13:88:26 | call to source : | semmle.label | call to source : |
195+
| summaries.rb:88:13:88:26 | call to source : | semmle.label | call to source : |
196+
| summaries.rb:89:6:89:6 | x [@value] : | semmle.label | x [@value] : |
197+
| summaries.rb:89:6:89:6 | x [@value] : | semmle.label | x [@value] : |
198+
| summaries.rb:89:6:89:16 | call to get_value | semmle.label | call to get_value |
199+
| summaries.rb:89:6:89:16 | call to get_value | semmle.label | call to get_value |
186200
subpaths
187201
invalidSpecComponent
188202
#select
@@ -227,6 +241,8 @@ invalidSpecComponent
227241
| summaries.rb:80:6:80:9 | ...[...] | summaries.rb:74:15:74:29 | call to source : | summaries.rb:80:6:80:9 | ...[...] | $@ | summaries.rb:74:15:74:29 | call to source : | call to source : |
228242
| summaries.rb:85:6:85:9 | ...[...] | summaries.rb:74:32:74:46 | call to source : | summaries.rb:85:6:85:9 | ...[...] | $@ | summaries.rb:74:32:74:46 | call to source : | call to source : |
229243
| summaries.rb:85:6:85:9 | ...[...] | summaries.rb:74:32:74:46 | call to source : | summaries.rb:85:6:85:9 | ...[...] | $@ | summaries.rb:74:32:74:46 | call to source : | call to source : |
244+
| summaries.rb:89:6:89:16 | call to get_value | summaries.rb:88:13:88:26 | call to source : | summaries.rb:89:6:89:16 | call to get_value | $@ | summaries.rb:88:13:88:26 | call to source : | call to source : |
245+
| summaries.rb:89:6:89:16 | call to get_value | summaries.rb:88:13:88:26 | call to source : | summaries.rb:89:6:89:16 | call to get_value | $@ | summaries.rb:88:13:88:26 | call to source : | call to source : |
230246
warning
231247
| CSV type row should have 5 columns but has 2: test;TooFewColumns |
232248
| CSV type row should have 5 columns but has 8: test;TooManyColumns;;;Member[Foo].Instance;too;many;columns |

ruby/ql/test/library-tests/dataflow/summaries/Summaries.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ private class StepsFromModel extends ModelInput::SummaryModelCsv {
6666
override predicate row(string row) {
6767
row =
6868
[
69+
";any;Method[set_value];Argument[0];Argument[self].Field[@value];value",
70+
";any;Method[get_value];Argument[self].Field[@value];ReturnValue;value",
6971
";;Member[Foo].Method[firstArg];Argument[0];ReturnValue;taint",
7072
";;Member[Foo].Method[secondArg];Argument[1];ReturnValue;taint",
7173
";;Member[Foo].Method[onlyWithoutBlock].WithoutBlock;Argument[0];ReturnValue;taint",

ruby/ql/test/library-tests/dataflow/summaries/summaries.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,8 @@ def userDefinedFunction(x, y)
8282
a.withoutElementOne()
8383
sink(a[0])
8484
sink(a[1])
85-
sink(a[2]) # $ hasValueFlow=elem2
85+
sink(a[2]) # $ hasValueFlow=elem2
86+
87+
x = Foo.new
88+
x.set_value(source("attr"))
89+
sink(x.get_value) # $ hasValueFlow=attr

0 commit comments

Comments
 (0)