mirror of
https://github.com/github/codeql.git
synced 2026-05-05 13:45:19 +02:00
Dynamic/JS: Add library for exporting models
This commit is contained in:
@@ -147,7 +147,11 @@ private predicate isPrivateAssignment(DataFlow::Node node) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isPrivateLike(API::Node node) { isPrivateAssignment(node.asSink()) }
|
||||
/**
|
||||
* Holds if `node` is the sink node corresponding to the right-hand side of a private declaration,
|
||||
* like a private field (`#field`) or class member with the `private` modifier.
|
||||
*/
|
||||
predicate isPrivateLike(API::Node node) { isPrivateAssignment(node.asSink()) }
|
||||
|
||||
bindingset[name]
|
||||
private int getNameBadness(string name) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
private import javascript
|
||||
private import internal.ApiGraphModels as Shared
|
||||
private import internal.ApiGraphModelsSpecific as Specific
|
||||
private import semmle.javascript.endpoints.EndpointNaming as EndpointNaming
|
||||
import Shared::ModelInput as ModelInput
|
||||
import Shared::ModelOutput as ModelOutput
|
||||
|
||||
@@ -55,3 +56,98 @@ private class TaintStepFromSummary extends TaintTracking::SharedTaintStep {
|
||||
summaryStepNodes(pred, succ, "taint")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies which parts of the API graph to export in `ModelExport`.
|
||||
*/
|
||||
signature module ModelExportSig {
|
||||
/**
|
||||
* Holds if the exported model should contain `node`, if it is publicly accessible.
|
||||
*
|
||||
* This ensures that all ways to access `node` will be exported in type models.
|
||||
*/
|
||||
predicate shouldContain(API::Node node);
|
||||
|
||||
/**
|
||||
* Holds if a named must be generated for `node` if it is to be included in the exported graph.
|
||||
*/
|
||||
default predicate mustBeNamed(API::Node node) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Module for exporting type models for a given set of nodes in the API graph.
|
||||
*/
|
||||
module ModelExport<ModelExportSig S> {
|
||||
private import codeql.mad.dynamic.GraphExport
|
||||
|
||||
private module GraphExportConfig implements GraphExportSig<API::Node> {
|
||||
predicate edge = Specific::apiGraphHasEdge/3;
|
||||
|
||||
predicate shouldContain = S::shouldContain/1;
|
||||
|
||||
predicate shouldNotContain(API::Node node) {
|
||||
EndpointNaming::isPrivateLike(node)
|
||||
or
|
||||
node instanceof API::Use
|
||||
}
|
||||
|
||||
predicate mustBeNamed(API::Node node) {
|
||||
node.getAValueReachingSink() instanceof DataFlow::ClassNode
|
||||
or
|
||||
node = API::Internal::getClassInstance(_)
|
||||
or
|
||||
S::mustBeNamed(node)
|
||||
}
|
||||
|
||||
predicate exposedName(API::Node node, string type, string path) {
|
||||
node = API::moduleExport(type) and path = ""
|
||||
}
|
||||
|
||||
predicate suggestedName(API::Node node, string type) {
|
||||
exists(string package, string name |
|
||||
(
|
||||
EndpointNaming::sinkHasPrimaryName(node, package, name) and
|
||||
not EndpointNaming::aliasDefinition(_, _, _, _, node)
|
||||
or
|
||||
EndpointNaming::aliasDefinition(_, _, package, name, node)
|
||||
) and
|
||||
type = EndpointNaming::renderName(package, name)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[host]
|
||||
predicate hasTypeSummary(API::Node host, string path) {
|
||||
exists(string methodName |
|
||||
functionReturnsReceiver(host.getMember(methodName).getAValueReachingSink()) and
|
||||
path = "Member[" + methodName + "].ReturnValue"
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate functionReturnsReceiver(DataFlow::FunctionNode func) {
|
||||
getAReceiverRef(func).flowsTo(func.getReturnNode())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::MethodCallNode getAReceiverCall(DataFlow::FunctionNode func) {
|
||||
result = getAReceiverRef(func).getAMethodCall()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate callReturnsReceiver(DataFlow::MethodCallNode call) {
|
||||
functionReturnsReceiver(call.getACallee().flow())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::SourceNode getAReceiverRef(DataFlow::FunctionNode func) {
|
||||
result = func.getReceiver()
|
||||
or
|
||||
result = getAReceiverCall(func) and
|
||||
callReturnsReceiver(result)
|
||||
}
|
||||
}
|
||||
|
||||
private module ExportedGraph = GraphExport<API::Node, GraphExportConfig>;
|
||||
|
||||
import ExportedGraph
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ private API::Node getNodeFromType(string type) {
|
||||
* Gets the API node identified by the first `n` tokens of `path` in the given `(type, path)` tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private API::Node getNodeFromPath(string type, AccessPath path, int n) {
|
||||
API::Node getNodeFromPath(string type, AccessPath path, int n) {
|
||||
isRelevantFullPath(type, path) and
|
||||
(
|
||||
n = 0 and
|
||||
|
||||
@@ -353,3 +353,23 @@ module ModelOutputSpecific {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the edge `pred -> succ` labelled with `path` exists in the API graph.
|
||||
*/
|
||||
bindingset[pred]
|
||||
predicate apiGraphHasEdge(API::Node pred, string path, API::Node succ) {
|
||||
exists(string name | succ = pred.getMember(name) and path = "Member[" + name + "]")
|
||||
or
|
||||
succ = pred.getUnknownMember() and path = "AnyMember"
|
||||
or
|
||||
succ = pred.getInstance() and path = "Instance"
|
||||
or
|
||||
succ = pred.getReturn() and path = "ReturnValue"
|
||||
or
|
||||
exists(int n | succ = pred.getParameter(n) |
|
||||
if pred instanceof API::Use then path = "Argument[" + n + "]" else path = "Parameter[" + n + "]"
|
||||
)
|
||||
or
|
||||
succ = pred.getPromised() and path = "Awaited"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user