Ruby: allow fields in flow summaries

This commit is contained in:
Arthur Baars
2022-05-25 15:42:51 +02:00
parent af428a1ac2
commit 033df767ef
5 changed files with 38 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ private import DataFlowDispatch
private import SsaImpl as SsaImpl
private import FlowSummaryImpl as FlowSummaryImpl
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import codeql.ruby.frameworks.data.ModelsAsData
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(NodeImpl n) { result = n.getEnclosingCallable() }
@@ -353,6 +354,17 @@ private module Cached {
name = any(InstanceVariable v).getName()
or
name = "@" + any(SetterMethodCall c).getTargetName()
or
// The following equation unfortunately leads to a non-monotonic recursion error:
// name = any(AccessPathToken a).getAnArgument("Field")
// Therefore, we use the following instead to extract the field names from the
// external model data. This, unfortunately, does not included any field names used
// in models defined in QL code.
exists(string input, string output |
ModelOutput::relevantSummaryModel(_, _, _, input, output, _)
|
name = [input, output].regexpFind("(?<=(^|\\.)Field\\[)[^\\]]+(?=\\])", _, _).trim()
)
}
/**

View File

@@ -98,6 +98,9 @@ SummaryComponent interpretComponentSpecific(AccessPathToken c) {
or
result = interpretElementArg(c.getAnArgument("Element"))
or
result =
FlowSummary::SummaryComponent::content(TSingletonContent(TFieldContent(c.getAnArgument("Field"))))
or
exists(ContentSet cs |
FlowSummary::SummaryComponent::content(cs) = interpretElementArg(c.getAnArgument("WithElement")) and
result = FlowSummary::SummaryComponent::withContent(cs)

View File

@@ -86,6 +86,12 @@ edges
| summaries.rb:82:1:82:1 | a [element 2] : | summaries.rb:82:1:82:1 | [post] a [element 2] : |
| summaries.rb:85:6:85:6 | a [element 2] : | summaries.rb:85:6:85:9 | ...[...] |
| summaries.rb:85:6:85:6 | a [element 2] : | summaries.rb:85:6:85:9 | ...[...] |
| summaries.rb:88:1:88:1 | [post] x [@value] : | summaries.rb:89:6:89:6 | x [@value] : |
| summaries.rb:88:1:88:1 | [post] x [@value] : | summaries.rb:89:6:89:6 | x [@value] : |
| summaries.rb:88:13:88:26 | call to source : | summaries.rb:88:1:88:1 | [post] x [@value] : |
| summaries.rb:88:13:88:26 | call to source : | summaries.rb:88:1:88:1 | [post] x [@value] : |
| summaries.rb:89:6:89:6 | x [@value] : | summaries.rb:89:6:89:16 | call to get_value |
| summaries.rb:89:6:89:6 | x [@value] : | summaries.rb:89:6:89:16 | call to get_value |
nodes
| summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : |
| summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : |
@@ -183,6 +189,14 @@ nodes
| summaries.rb:85:6:85:6 | a [element 2] : | semmle.label | a [element 2] : |
| summaries.rb:85:6:85:9 | ...[...] | semmle.label | ...[...] |
| summaries.rb:85:6:85:9 | ...[...] | semmle.label | ...[...] |
| summaries.rb:88:1:88:1 | [post] x [@value] : | semmle.label | [post] x [@value] : |
| summaries.rb:88:1:88:1 | [post] x [@value] : | semmle.label | [post] x [@value] : |
| summaries.rb:88:13:88:26 | call to source : | semmle.label | call to source : |
| summaries.rb:88:13:88:26 | call to source : | semmle.label | call to source : |
| summaries.rb:89:6:89:6 | x [@value] : | semmle.label | x [@value] : |
| summaries.rb:89:6:89:6 | x [@value] : | semmle.label | x [@value] : |
| summaries.rb:89:6:89:16 | call to get_value | semmle.label | call to get_value |
| summaries.rb:89:6:89:16 | call to get_value | semmle.label | call to get_value |
subpaths
invalidSpecComponent
#select
@@ -227,6 +241,8 @@ invalidSpecComponent
| 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 : |
| 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 : |
| 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 : |
| 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 : |
| 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 : |
warning
| CSV type row should have 5 columns but has 2: test;TooFewColumns |
| CSV type row should have 5 columns but has 8: test;TooManyColumns;;;Member[Foo].Instance;too;many;columns |

View File

@@ -66,6 +66,8 @@ private class StepsFromModel extends ModelInput::SummaryModelCsv {
override predicate row(string row) {
row =
[
";any;Method[set_value];Argument[0];Argument[self].Field[@value];value",
";any;Method[get_value];Argument[self].Field[@value];ReturnValue;value",
";;Member[Foo].Method[firstArg];Argument[0];ReturnValue;taint",
";;Member[Foo].Method[secondArg];Argument[1];ReturnValue;taint",
";;Member[Foo].Method[onlyWithoutBlock].WithoutBlock;Argument[0];ReturnValue;taint",

View File

@@ -82,4 +82,8 @@ sink(b[2])
a.withoutElementOne()
sink(a[0])
sink(a[1])
sink(a[2]) # $ hasValueFlow=elem2
sink(a[2]) # $ hasValueFlow=elem2
x = Foo.new
x.set_value(source("attr"))
sink(x.get_value) # $ hasValueFlow=attr