Skip to content

Commit 0879b6a

Browse files
committed
Ruby: Fix Argument[any,any-named] handling for path component in MaD
1 parent 7784b9f commit 0879b6a

File tree

6 files changed

+42
-4
lines changed

6 files changed

+42
-4
lines changed

ruby/ql/lib/codeql/ruby/ApiGraphs.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,20 @@ module API {
780780
or
781781
pos.isBlock() and
782782
result = Label::blockParameter()
783+
or
784+
pos.isAny() and
785+
(
786+
result = Label::parameter(_)
787+
or
788+
result = Label::keywordParameter(_)
789+
or
790+
result = Label::blockParameter()
791+
// NOTE: `self` should NOT be included, as described in the QLDoc for `isAny()`
792+
)
793+
// TODO: needs handling of `self` ArgumentPosition
794+
// or
795+
// pos.isSelf() and
796+
// ...
783797
}
784798

785799
/** Gets the API graph label corresponding to the given parameter position. */

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ private module Cached {
259259
exists(any(Call c).getKeywordArgument(name))
260260
or
261261
FlowSummaryImplSpecific::ParsePositions::isParsedKeywordParameterPosition(_, name)
262-
}
262+
} or
263+
TAnyArgumentPosition()
263264

264265
cached
265266
newtype TParameterPosition =
@@ -512,6 +513,12 @@ class ArgumentPosition extends TArgumentPosition {
512513
/** Holds if this position represents a keyword argument named `name`. */
513514
predicate isKeyword(string name) { this = TKeywordArgumentPosition(name) }
514515

516+
/**
517+
* Holds if this position represents any argument, except `self` arguments. This
518+
* includes both positional, named, and block arguments.
519+
*/
520+
predicate isAny() { this = TAnyArgumentPosition() }
521+
515522
/** Gets a textual representation of this position. */
516523
string toString() {
517524
this.isSelf() and result = "self"
@@ -521,6 +528,8 @@ class ArgumentPosition extends TArgumentPosition {
521528
exists(int pos | this.isPositional(pos) and result = "position " + pos)
522529
or
523530
exists(string name | this.isKeyword(name) and result = "keyword " + name)
531+
or
532+
this.isAny() and result = "any"
524533
}
525534
}
526535

@@ -540,4 +549,6 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
540549
exists(string name | ppos.isKeyword(name) and apos.isKeyword(name))
541550
or
542551
ppos.isAny() and not apos.isSelf()
552+
or
553+
apos.isAny() and not ppos.isSelf()
543554
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ ArgumentPosition parseParamBody(string s) {
257257
or
258258
s = "block" and
259259
result.isBlock()
260+
or
261+
s = "any" and
262+
result.isAny()
263+
or
264+
s = "any-named" and
265+
result.isKeyword(_)
260266
}
261267

262268
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */

ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsSpecific.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) {
115115
or
116116
token.getName() = "Parameter" and
117117
result =
118-
node.getASuccessor(API::Label::getLabelFromArgumentPosition(FlowSummaryImplSpecific::parseParamBody(token
118+
node.getASuccessor(API::Label::getLabelFromParameterPosition(FlowSummaryImplSpecific::parseArgBody(token
119119
.getAnArgument())))
120120
// Note: The "Element" token is not implemented yet, as it ultimately requires type-tracking and
121121
// API graphs to be aware of the steps involving Element contributed by the standard library model.
@@ -129,7 +129,7 @@ bindingset[token]
129129
API::Node getExtraSuccessorFromInvoke(InvokeNode node, AccessPathToken token) {
130130
token.getName() = "Argument" and
131131
result =
132-
node.getASuccessor(API::Label::getLabelFromParameterPosition(FlowSummaryImplSpecific::parseArgBody(token
132+
node.getASuccessor(API::Label::getLabelFromArgumentPosition(FlowSummaryImplSpecific::parseParamBody(token
133133
.getAnArgument())))
134134
}
135135

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ edges
3030
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:102:16:102:22 | tainted |
3131
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:103:21:103:27 | tainted |
3232
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:103:21:103:27 | tainted |
33+
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:106:26:106:32 | tainted |
34+
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:106:26:106:32 | tainted |
3335
| summaries.rb:1:20:1:36 | call to source : | summaries.rb:1:11:1:36 | call to identity : |
3436
| summaries.rb:1:20:1:36 | call to source : | summaries.rb:1:11:1:36 | call to identity : |
3537
| summaries.rb:4:12:7:3 | call to apply_block : | summaries.rb:9:6:9:13 | tainted2 |
@@ -97,6 +99,7 @@ edges
9799
| summaries.rb:93:16:93:22 | [post] tainted : | summaries.rb:99:14:99:20 | tainted : |
98100
| summaries.rb:93:16:93:22 | [post] tainted : | summaries.rb:102:16:102:22 | tainted |
99101
| summaries.rb:93:16:93:22 | [post] tainted : | summaries.rb:103:21:103:27 | tainted |
102+
| summaries.rb:93:16:93:22 | [post] tainted : | summaries.rb:106:26:106:32 | tainted |
100103
| summaries.rb:93:16:93:22 | tainted : | summaries.rb:93:16:93:22 | [post] tainted : |
101104
| summaries.rb:93:16:93:22 | tainted : | summaries.rb:93:25:93:25 | [post] y : |
102105
| summaries.rb:93:16:93:22 | tainted : | summaries.rb:93:33:93:33 | [post] z : |
@@ -216,6 +219,8 @@ nodes
216219
| summaries.rb:102:16:102:22 | tainted | semmle.label | tainted |
217220
| summaries.rb:103:21:103:27 | tainted | semmle.label | tainted |
218221
| summaries.rb:103:21:103:27 | tainted | semmle.label | tainted |
222+
| summaries.rb:106:26:106:32 | tainted | semmle.label | tainted |
223+
| summaries.rb:106:26:106:32 | tainted | semmle.label | tainted |
219224
subpaths
220225
invalidSpecComponent
221226
#select
@@ -268,6 +273,8 @@ invalidSpecComponent
268273
| summaries.rb:102:16:102:22 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:102:16:102:22 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
269274
| summaries.rb:103:21:103:27 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:103:21:103:27 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
270275
| summaries.rb:103:21:103:27 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:103:21:103:27 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
276+
| summaries.rb:106:26:106:32 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:106:26:106:32 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
277+
| summaries.rb:106:26:106:32 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:106:26:106:32 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
271278
warning
272279
| CSV type row should have 5 columns but has 2: test;TooFewColumns |
273280
| 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.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,4 @@ def userDefinedFunction(x, y)
103103
Foo.sinkAnyArg(key: tainted) # $ hasValueFlow=tainted
104104

105105
Foo.sinkAnyNamedArg(tainted)
106-
Foo.sinkAnyNamedArg(key: tainted) # $ MISSING: hasValueFlow=tainted
106+
Foo.sinkAnyNamedArg(key: tainted) # $ hasValueFlow=tainted

0 commit comments

Comments
 (0)