mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
Ruby: add TypeModel hook for adding type-defs from CodeQL
This commit is contained in:
@@ -72,6 +72,8 @@ private class Unit = Specific::Unit;
|
||||
|
||||
private module API = Specific::API;
|
||||
|
||||
private module DataFlow = Specific::DF;
|
||||
|
||||
private import Specific::AccessPathSyntax
|
||||
|
||||
/** Module containing hooks for providing input data to be interpreted as a model. */
|
||||
@@ -156,6 +158,22 @@ module ModelInput {
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional type model rows from CodeQL models.
|
||||
*/
|
||||
class TypeModel extends Unit {
|
||||
/**
|
||||
* Gets a data-flow node that is a source of the type `package;type`.
|
||||
*/
|
||||
DataFlow::Node getASource(string package, string type) { none() }
|
||||
|
||||
/**
|
||||
* Gets a data flow node that is a sink of the type `package;type`,
|
||||
* usually because it is an argument passed to a parameter of that type.
|
||||
*/
|
||||
DataFlow::Node getASink(string package, string type) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional type variable model rows.
|
||||
*/
|
||||
@@ -368,6 +386,58 @@ private predicate invocationMatchesCallSiteFilter(Specific::InvokeNode invoke, A
|
||||
Specific::invocationMatchesExtraCallSiteFilter(invoke, token)
|
||||
}
|
||||
|
||||
private class TypeModelUseEntry extends API::EntryPoint {
|
||||
private string package;
|
||||
private string type;
|
||||
|
||||
TypeModelUseEntry() {
|
||||
exists(any(TypeModel tm).getASource(package, type)) and
|
||||
this = "TypeModelUseEntry;" + package + ";" + type
|
||||
}
|
||||
|
||||
override DataFlow::LocalSourceNode getASource() {
|
||||
result = any(TypeModel tm).getASource(package, type)
|
||||
}
|
||||
|
||||
API::Node getNodeForType(string package_, string type_) {
|
||||
package = package_ and type = type_ and result = this.getANode()
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeModelDefEntry extends API::EntryPoint {
|
||||
private string package;
|
||||
private string type;
|
||||
|
||||
TypeModelDefEntry() {
|
||||
exists(any(TypeModel tm).getASink(package, type)) and
|
||||
this = "TypeModelDefEntry;" + package + ";" + type
|
||||
}
|
||||
|
||||
override DataFlow::Node getASink() { result = any(TypeModel tm).getASink(package, type) }
|
||||
|
||||
API::Node getNodeForType(string package_, string type_) {
|
||||
package = package_ and type = type_ and result = this.getANode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an API node identified by the given `(package,type)` pair.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private API::Node getNodeFromType(string package, string type) {
|
||||
exists(string package2, string type2, AccessPath path2 |
|
||||
typeModel(package, type, package2, type2, path2) and
|
||||
result = getNodeFromPath(package2, type2, path2, path2.getNumToken())
|
||||
)
|
||||
or
|
||||
result = any(TypeModelUseEntry e).getNodeForType(package, type)
|
||||
or
|
||||
result = any(TypeModelDefEntry e).getNodeForType(package, type)
|
||||
or
|
||||
isRelevantFullPath(package, type, _) and
|
||||
result = Specific::getExtraNodeFromPath(package, type, _, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the API node identified by the first `n` tokens of `path` in the given `(package, type, path)` tuple.
|
||||
*/
|
||||
@@ -376,12 +446,8 @@ private API::Node getNodeFromPath(string package, string type, AccessPath path,
|
||||
isRelevantFullPath(package, type, path) and
|
||||
(
|
||||
n = 0 and
|
||||
exists(string package2, string type2, AccessPath path2 |
|
||||
typeModel(package, type, package2, type2, path2) and
|
||||
result = getNodeFromPath(package2, type2, path2, path2.getNumToken())
|
||||
)
|
||||
result = getNodeFromType(package, type)
|
||||
or
|
||||
// Language-specific cases, such as handling of global variables
|
||||
result = Specific::getExtraNodeFromPath(package, type, path, n)
|
||||
)
|
||||
or
|
||||
@@ -581,12 +647,7 @@ module ModelOutput {
|
||||
* Holds if `node` is seen as an instance of `(package,type)` due to a type definition
|
||||
* contributed by a CSV model.
|
||||
*/
|
||||
API::Node getATypeNode(string package, string type) {
|
||||
exists(string package2, string type2, AccessPath path |
|
||||
typeModel(package, type, package2, type2, path) and
|
||||
result = getNodeFromPath(package2, type2, path)
|
||||
)
|
||||
}
|
||||
API::Node getATypeNode(string package, string type) { result = getNodeFromType(package, type) }
|
||||
|
||||
/**
|
||||
* Gets an error message relating to an invalid CSV row in a model.
|
||||
|
||||
@@ -29,6 +29,7 @@ class Unit = DataFlowPrivate::Unit;
|
||||
// Re-export libraries needed by ApiGraphModels.qll
|
||||
import codeql.ruby.ApiGraphs
|
||||
import codeql.ruby.dataflow.internal.AccessPathSyntax as AccessPathSyntax
|
||||
import codeql.ruby.dataflow.internal.DataFlowPublic as DF
|
||||
private import AccessPathSyntax
|
||||
private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||
|
||||
@@ -32,6 +32,8 @@ edges
|
||||
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:114:21:114:27 | tainted |
|
||||
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:117:26:117:32 | tainted |
|
||||
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:117:26:117:32 | tainted |
|
||||
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:119:23:119:29 | tainted |
|
||||
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:119:23:119:29 | tainted |
|
||||
| summaries.rb:1:20:1:36 | call to source : | summaries.rb:1:11:1:36 | call to identity : |
|
||||
| summaries.rb:1:20:1:36 | call to source : | summaries.rb:1:11:1:36 | call to identity : |
|
||||
| summaries.rb:4:12:7:3 | call to apply_block : | summaries.rb:9:6:9:13 | tainted2 |
|
||||
@@ -109,6 +111,7 @@ edges
|
||||
| summaries.rb:104:16:104:22 | [post] tainted : | summaries.rb:113:16:113:22 | tainted |
|
||||
| summaries.rb:104:16:104:22 | [post] tainted : | summaries.rb:114:21:114:27 | tainted |
|
||||
| summaries.rb:104:16:104:22 | [post] tainted : | summaries.rb:117:26:117:32 | tainted |
|
||||
| summaries.rb:104:16:104:22 | [post] tainted : | summaries.rb:119:23:119:29 | tainted |
|
||||
| summaries.rb:104:16:104:22 | tainted : | summaries.rb:104:16:104:22 | [post] tainted : |
|
||||
| summaries.rb:104:16:104:22 | tainted : | summaries.rb:104:25:104:25 | [post] y : |
|
||||
| summaries.rb:104:16:104:22 | tainted : | summaries.rb:104:33:104:33 | [post] z : |
|
||||
@@ -242,6 +245,8 @@ nodes
|
||||
| summaries.rb:114:21:114:27 | tainted | semmle.label | tainted |
|
||||
| summaries.rb:117:26:117:32 | tainted | semmle.label | tainted |
|
||||
| summaries.rb:117:26:117:32 | tainted | semmle.label | tainted |
|
||||
| summaries.rb:119:23:119:29 | tainted | semmle.label | tainted |
|
||||
| summaries.rb:119:23:119:29 | tainted | semmle.label | tainted |
|
||||
subpaths
|
||||
invalidSpecComponent
|
||||
#select
|
||||
@@ -299,6 +304,8 @@ invalidSpecComponent
|
||||
| summaries.rb:114:21:114:27 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:114:21:114:27 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||
| summaries.rb:117:26:117:32 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:117:26:117:32 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||
| summaries.rb:117:26:117:32 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:117:26:117:32 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||
| summaries.rb:119:23:119:29 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:119:23:119:29 | tainted | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||
| summaries.rb:119:23:119:29 | tainted | summaries.rb:1:20:1:36 | call to source : | summaries.rb:119:23:119:29 | tainted | $@ | summaries.rb:1:20:1:36 | 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 |
|
||||
|
||||
@@ -102,6 +102,14 @@ private class TypeFromModel extends ModelInput::TypeModelCsv {
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeFromCodeQL extends ModelInput::TypeModel {
|
||||
override DataFlow::Node getASource(string package, string type) {
|
||||
package = "test" and
|
||||
type = "FooOrBar" and
|
||||
result.asExpr().getExpr().getConstantValue().getString() = "magic_string"
|
||||
}
|
||||
}
|
||||
|
||||
private class InvalidTypeModel extends ModelInput::TypeModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
|
||||
@@ -115,3 +115,6 @@ Foo.sinkAnyArg(key: tainted) # $ hasValueFlow=tainted
|
||||
|
||||
Foo.sinkAnyNamedArg(tainted)
|
||||
Foo.sinkAnyNamedArg(key: tainted) # $ hasValueFlow=tainted
|
||||
|
||||
"magic_string".method(tainted) # $ hasValueFlow=tainted
|
||||
"magic_string2".method(tainted)
|
||||
|
||||
Reference in New Issue
Block a user