Skip to content

Commit 7f82056

Browse files
committed
Ruby: verify tokens in identifying access path
1 parent 97ca115 commit 7f82056

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,42 @@ Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPa
363363
result = getInvocationFromPath(package, type, path, path.getNumToken())
364364
}
365365

366+
/**
367+
* Holds if `name` is a valid name for an access path token in the identifying access path.
368+
*/
369+
bindingset[name]
370+
predicate isValidTokenNameInIdentifyingAccessPath(string name) {
371+
name = ["Argument", "Parameter", "ReturnValue", "WithArity"]
372+
or
373+
Specific::isExtraValidTokenNameInIdentifyingAccessPath(name)
374+
}
375+
376+
/**
377+
* Holds if `name` is a valid name for an access path token with no arguments, occuring
378+
* in an identifying access path.
379+
*/
380+
bindingset[name]
381+
predicate isValidNoArgumentTokenInIdentifyingAccessPath(string name) {
382+
name = "ReturnValue"
383+
or
384+
Specific::isExtraValidNoArgumentTokenInIdentifyingAccessPath(name)
385+
}
386+
387+
/**
388+
* Holds if `argument` is a valid argument to an access path token with the given `name`, occurring
389+
* in an identifying access path.
390+
*/
391+
bindingset[name, argument]
392+
predicate isValidTokenArgumentInIdentifyingAccessPath(string name, string argument) {
393+
name = ["Argument", "Parameter"] and
394+
argument.regexpMatch("(N-|-)?\\d+(\\.\\.(N-|-)?\\d+)?")
395+
or
396+
name = "WithArity" and
397+
argument.regexpMatch("\\d+(\\.\\.\\d+)?")
398+
or
399+
Specific::isExtraValidTokenArgumentInIdentifyingAccessPath(name, argument)
400+
}
401+
366402
/**
367403
* Module providing access to the imported models in terms of API graph nodes.
368404
*/
@@ -441,5 +477,27 @@ module ModelOutput {
441477
"CSV " + kind + " row should have " + expectedArity + " columns but has " + actualArity +
442478
": " + row
443479
)
480+
or
481+
// Check names and arguments of access path tokens
482+
exists(AccessPath path, AccessPathToken token |
483+
isRelevantFullPath(_, _, path) and
484+
token = path.getToken(_)
485+
|
486+
not isValidTokenNameInIdentifyingAccessPath(token.getName()) and
487+
result = "Invalid token name '" + token.getName() + "' in access path: " + path
488+
or
489+
isValidTokenNameInIdentifyingAccessPath(token.getName()) and
490+
exists(string argument |
491+
argument = token.getAnArgument() and
492+
not isValidTokenArgumentInIdentifyingAccessPath(token.getName(), argument) and
493+
result =
494+
"Invalid argument '" + argument + "' in token '" + token + "' in access path: " + path
495+
)
496+
or
497+
isValidTokenNameInIdentifyingAccessPath(token.getName()) and
498+
token.getNumArgument() = 0 and
499+
not isValidNoArgumentTokenInIdentifyingAccessPath(token.getName()) and
500+
result = "Invalid token '" + token + "' is missing its arguments, in access path: " + path
501+
)
444502
}
445503
}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,29 @@ class InvokeNode extends API::MethodAccessNode {
137137

138138
/** Gets the `InvokeNode` corresponding to a specific invocation of `node`. */
139139
InvokeNode getAnInvocationOf(API::Node node) { result = node }
140+
141+
/**
142+
* Holds if `name` is a valid name for an access path token in the identifying access path.
143+
*/
144+
bindingset[name]
145+
predicate isExtraValidTokenNameInIdentifyingAccessPath(string name) {
146+
name = ["Member", "Method", "Instance", "WithBlock", "WithoutBlock"]
147+
}
148+
149+
/**
150+
* Holds if `name` is a valid name for an access path token with no arguments, occuring
151+
* in an identifying access path.
152+
*/
153+
predicate isExtraValidNoArgumentTokenInIdentifyingAccessPath(string name) {
154+
name = ["Instance", "WithBlock", "WithoutBlock"]
155+
}
156+
157+
/**
158+
* Holds if `argument` is a valid argument to an access path token with the given `name`, occurring
159+
* in an identifying access path.
160+
*/
161+
bindingset[name, argument]
162+
predicate isExtraValidTokenArgumentInIdentifyingAccessPath(string name, string argument) {
163+
name = ["Member", "Method"] and
164+
argument = any(string s)
165+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,8 @@ invalidOutputSpecComponent
8484
warning
8585
| CSV type row should have 5 columns but has 2: test;TooFewColumns |
8686
| CSV type row should have 5 columns but has 8: test;TooManyColumns;;;Member[Foo].Instance;too;many;columns |
87+
| Invalid argument '0-1' in token 'Argument[0-1]' in access path: Method[foo].Argument[0-1] |
88+
| Invalid argument '*' in token 'Argument[*]' in access path: Method[foo].Argument[*] |
89+
| Invalid token 'Argument' is missing its arguments, in access path: Method[foo].Argument |
90+
| Invalid token 'Member' is missing its arguments, in access path: Method[foo].Member |
91+
| Invalid token name 'Arg' in access path: Method[foo].Arg[0] |

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ private class InvalidTypeModel extends ModelInput::TypeModelCsv {
9797
[
9898
"test;TooManyColumns;;;Member[Foo].Instance;too;many;columns", //
9999
"test;TooFewColumns", //
100+
"test;X;test;Y;Method[foo].Arg[0]", //
101+
"test;X;test;Y;Method[foo].Argument[0-1]", //
102+
"test;X;test;Y;Method[foo].Argument[*]", //
103+
"test;X;test;Y;Method[foo].Argument", //
104+
"test;X;test;Y;Method[foo].Member", //
100105
]
101106
}
102107
}

0 commit comments

Comments
 (0)