mirror of
https://github.com/github/codeql.git
synced 2026-05-25 00:27:09 +02:00
PS: Use ! to mark static members/methods.
This commit is contained in:
@@ -326,19 +326,25 @@ module API {
|
||||
|
||||
/** A node representing a module/class object with epsilon edges to its descendents. */
|
||||
private class ModuleNode extends Node, Impl::MkModule {
|
||||
/** Gets the module represented by this API node. */
|
||||
string getModule() { this = Impl::MkModule(result) }
|
||||
string qualifiedModule;
|
||||
int n;
|
||||
|
||||
ModuleNode() { this = Impl::MkModule(qualifiedModule, n) }
|
||||
|
||||
ModuleNode getNext() { result = Impl::MkModule(qualifiedModule, n + 1) }
|
||||
|
||||
ModuleNode getPred() { result.getNext() = this }
|
||||
|
||||
string getComponent() { result = qualifiedModule.splitAt(".", n) }
|
||||
|
||||
string getModule() {
|
||||
not exists(this.getPred()) and
|
||||
result = this.getComponent()
|
||||
or
|
||||
result = this.getPred().getModule() + "." + this.getComponent()
|
||||
}
|
||||
|
||||
override string toString() { result = "Module(" + this.getModule() + ")" }
|
||||
|
||||
TypeNode getType(string name) { result.getType() = this.getModule() + "." + name } // TODO: Check that name exists in module
|
||||
}
|
||||
|
||||
private class TypeNode extends Node, Impl::MkType {
|
||||
/** Gets the type represented by this API node. */
|
||||
string getType() { this = Impl::MkType(result) }
|
||||
|
||||
override string toString() { result = "Type(" + this.getType() + ")" }
|
||||
}
|
||||
|
||||
/** A node representing instances of a module/class with epsilon edges to its ancestors. */
|
||||
@@ -413,13 +419,7 @@ module API {
|
||||
* Gets the node that represents the module with qualified
|
||||
* name `qualifiedModule`.
|
||||
*/
|
||||
ModuleNode mod(string qualifiedModule) { result = Impl::MkModule(qualifiedModule) }
|
||||
|
||||
/**
|
||||
* Gets the node that represents the type with qualified
|
||||
* name `qualifiedType`.
|
||||
*/
|
||||
TypeNode type(string qualifiedType) { result = Impl::MkType(qualifiedType) }
|
||||
ModuleNode mod(string qualifiedModule, int n) { result = Impl::MkModule(qualifiedModule, n) }
|
||||
|
||||
/**
|
||||
* Gets an unqualified call at the top-level with the given method name.
|
||||
@@ -466,26 +466,31 @@ module API {
|
||||
|
||||
cached
|
||||
private module Impl {
|
||||
|
||||
private predicate isModule(string s, int n) {
|
||||
(
|
||||
any(UsingStmt using).getName() = s
|
||||
or
|
||||
any(Cmd cmd).getNamespaceQualifier() = s
|
||||
or
|
||||
any(TypeNameExpr tn).getName() = s
|
||||
or
|
||||
any(ModuleManifest manifest).getModuleName() = s
|
||||
) and
|
||||
exists(s.splitAt(".", n))
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TApiNode =
|
||||
/** The root of the API graph. */
|
||||
MkRoot() or
|
||||
/** The method accessed at `call`, synthetically treated as a separate object. */
|
||||
MkMethodAccessNode(DataFlow::CallNode call) or
|
||||
MkModule(string qualifiedModule) {
|
||||
any(UsingStmt using).getName() = qualifiedModule
|
||||
or
|
||||
any(Cmd cmd).getNamespaceQualifier() = qualifiedModule
|
||||
or
|
||||
any(TypeNameExpr tn).getName() = qualifiedModule
|
||||
or
|
||||
any(ModuleManifest manifest).getModuleName() = qualifiedModule
|
||||
} or
|
||||
MkType(string qualifiedType) { any(ConstantValue cv).asString() = qualifiedType } or // TODO
|
||||
MkModule(string qualifiedModule, int n) { isModule(qualifiedModule, n) } or
|
||||
/** Instances of `mod` with epsilon edges to its ancestors. */
|
||||
MkInstanceUp(string qualifiedType) { exists(MkType(qualifiedType)) } or
|
||||
MkInstanceUp(string qualifiedType) { exists(MkModule(qualifiedType, _)) } or
|
||||
/** Instances of `mod` with epsilon edges to its descendents, and to its upward node. */
|
||||
MkInstanceDown(string qualifiedType) { exists(MkType(qualifiedType)) } or
|
||||
MkInstanceDown(string qualifiedType) { exists(MkModule(qualifiedType, _)) } or
|
||||
/** Intermediate node for following forward data flow. */
|
||||
MkForwardNode(DataFlow::LocalSourceNode node, TypeTracker t) { isReachable(node, t) } or
|
||||
/** Intermediate node for following backward data flow. */
|
||||
@@ -525,14 +530,6 @@ module API {
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate typeEdge(Node pred, string name, Node succ) {
|
||||
exists(ModuleNode mod |
|
||||
pred = mod and
|
||||
succ = mod.getType(name)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate memberEdge(Node pred, string name, Node succ) {
|
||||
exists(MemberExpr member | succ = getForwardStartNode(getNodeFromExpr(member)) |
|
||||
@@ -546,8 +543,9 @@ module API {
|
||||
exists(DataFlow::CallNode call | succ = MkMethodAccessNode(call) and name = call.getName() |
|
||||
pred = getForwardEndNode(getALocalSourceStrict(call.getQualifier()))
|
||||
or
|
||||
exists(string qualifiedModule, ModuleManifest manifest |
|
||||
pred = mod(qualifiedModule) and
|
||||
exists(string qualifiedModule, ModuleManifest manifest, int n |
|
||||
pred = mod(qualifiedModule, n) and
|
||||
not exists(mod(qualifiedModule, n + 1)) and
|
||||
manifest.getModuleName() = qualifiedModule
|
||||
|
|
||||
manifest.getACmdLetToExport() = name
|
||||
@@ -647,8 +645,15 @@ module API {
|
||||
|
||||
cached
|
||||
predicate instanceEdge(Node pred, Node succ) {
|
||||
// An instance of a type
|
||||
exists(string qualifiedType | pred = MkType(qualifiedType) |
|
||||
exists(string qualifiedType, int n |
|
||||
pred = MkModule(qualifiedType, n) and
|
||||
not exists(MkModule(qualifiedType, n + 1))
|
||||
|
|
||||
exists(DataFlow::TypeNameNode typeName |
|
||||
typeName.getTypeName() = qualifiedType and
|
||||
succ = getForwardStartNode(typeName)
|
||||
)
|
||||
or
|
||||
exists(DataFlow::ObjectCreationNode objCreation |
|
||||
objCreation.getConstructedTypeName() = qualifiedType and
|
||||
succ = getForwardStartNode(objCreation)
|
||||
@@ -659,15 +664,6 @@ module API {
|
||||
succ = getForwardStartNode(p)
|
||||
)
|
||||
)
|
||||
or
|
||||
// A use of a module (or static type?)
|
||||
// TODO: Consider implicit module qualiifers and use instance on all of them
|
||||
exists(string qualifiedType, DataFlow::TypeNameNode typeName |
|
||||
pred = MkModule(qualifiedType) and
|
||||
typeName.getTypeName() = qualifiedType
|
||||
|
|
||||
succ = getForwardStartNode(typeName)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -610,7 +610,13 @@ module StmtNodes {
|
||||
|
||||
final override ExprCfgNode getCommand() { s.hasCfgChild(s.getCommand(), this, result) }
|
||||
|
||||
final override string getName() { result = s.getCmdName().getValue().getValue() }
|
||||
final override string getName() { result = s.getCommandName() }
|
||||
|
||||
/** Holds if the command is qualified. */
|
||||
predicate isQualified() { s.isQualified() }
|
||||
|
||||
/** Gets the namespace qualifier of this command, if any. */
|
||||
string getNamespaceQualifier() { result = s.getNamespaceQualifier() }
|
||||
}
|
||||
|
||||
/** A control-flow node that wraps a call to operator `&` */
|
||||
|
||||
@@ -202,6 +202,7 @@ private module Cached {
|
||||
isProcessPropertyByNameNode(iter, _)
|
||||
} or
|
||||
TScriptBlockNode(ScriptBlock scriptBlock) or
|
||||
TTypePathNode(int n, CfgNode cfg) { isTypePathNode(_, n, cfg) } or
|
||||
TForbiddenRecursionGuard() {
|
||||
none() and
|
||||
// We want to prune irrelevant models before materialising data flow nodes, so types contributed
|
||||
@@ -1148,6 +1149,64 @@ class ScriptBlockNode extends TScriptBlockNode, NodeImpl {
|
||||
override predicate nodeIsHidden() { any() }
|
||||
}
|
||||
|
||||
private predicate isTypePathNode(string type, int n, CfgNode cfg) {
|
||||
exists(CfgNodes::ExprNodes::TypeNameCfgNode typeName, string s |
|
||||
cfg = typeName and
|
||||
type = typeName.getTypeName() and
|
||||
s = type.splitAt(".", n)
|
||||
)
|
||||
or
|
||||
exists(CfgNodes::StmtNodes::CmdCfgNode cmd, string s |
|
||||
cfg = cmd.getCommand() and
|
||||
type = cmd.getNamespaceQualifier() and
|
||||
s = type.splitAt(".", n)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A dataflow node that represents a component of a type or module path.
|
||||
*
|
||||
* For example, `System`, `System.Management`, `System.Management.Automation`,
|
||||
* and `System.Management.Automation.PowerShell` in the type
|
||||
* name `[System.Management.Automation.PowerShell]`.
|
||||
*/
|
||||
class TypePathNodeImpl extends TTypePathNode, NodeImpl {
|
||||
int n;
|
||||
CfgNode cfg;
|
||||
|
||||
TypePathNodeImpl() { this = TTypePathNode(n, cfg) }
|
||||
|
||||
string getType() { isTypePathNode(result, n, cfg) }
|
||||
|
||||
predicate isComplete() { not exists(this.getNext()) }
|
||||
|
||||
int getIndex() { result = n }
|
||||
|
||||
string getComponent() { result = this.getType().splitAt(".", n) }
|
||||
|
||||
override CfgScope getCfgScope() { result = cfg.getScope() }
|
||||
|
||||
override Location getLocationImpl() { result = cfg.getLocation() }
|
||||
|
||||
override string toStringImpl() {
|
||||
not exists(this.getPrev()) and
|
||||
result = this.getComponent()
|
||||
or
|
||||
result = this.getPrev() + "." + this.getComponent()
|
||||
}
|
||||
|
||||
override predicate nodeIsHidden() { any() }
|
||||
|
||||
TypePathNodeImpl getNext() { result = TTypePathNode(n + 1, cfg) }
|
||||
|
||||
TypePathNodeImpl getPrev() { result.getNext() = this }
|
||||
|
||||
TypePathNodeImpl getConstant(string s) {
|
||||
s = result.getComponent() and
|
||||
result = this.getNext()
|
||||
}
|
||||
}
|
||||
|
||||
/** A node that performs a type cast. */
|
||||
class CastNode extends Node {
|
||||
CastNode() { none() }
|
||||
|
||||
@@ -193,6 +193,21 @@ class PostUpdateNode extends Node {
|
||||
Node getPreUpdateNode() { result = pre }
|
||||
}
|
||||
|
||||
/**
|
||||
* A dataflow node that represents a component of a type or module path.
|
||||
*
|
||||
* For example, `System`, `System.Management`, `System.Management.Automation`,
|
||||
* and `System.Management.Automation.PowerShell` in the type
|
||||
* name `[System.Management.Automation.PowerShell]`.
|
||||
*/
|
||||
class TypePathNode extends Node instanceof TypePathNodeImpl {
|
||||
string getComponent() { result = super.getComponent() }
|
||||
|
||||
TypePathNode getConstant(string s) { result = super.getConstant(s) }
|
||||
|
||||
API::Node track() { result = API::mod(super.getType(), super.getIndex()) }
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
|
||||
@@ -3,4 +3,4 @@ extensions:
|
||||
pack: microsoft-sdl/powershell-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["Microsoft.PowerShell.Utility", "Method[Read-Host].ReturnValue", "stdin"]
|
||||
- ["Microsoft.PowerShell.Utility!", "Method[Read-Host].ReturnValue", "stdin"]
|
||||
|
||||
@@ -3,4 +3,4 @@ extensions:
|
||||
pack: microsoft-sdl/powershell-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["Microsoft.Win32.Registry", "Method[GetValue]", "windows-registry"]
|
||||
- ["Microsoft.Win32.Registry!", "Method[GetValue]", "windows-registry"]
|
||||
@@ -3,6 +3,6 @@ extensions:
|
||||
pack: microsoft-sdl/powershell-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["Microsoft.Win32.RegistryKey", "Instance.Method[GetValue].ReturnValue", "windows-registry"]
|
||||
- ["Microsoft.Win32.RegistryKey", "Instance.Method[GetValueNames].ReturnValue", "windows-registry"]
|
||||
- ["Microsoft.Win32.RegistryKey", "Instance.Method[GetSubKeyNames].ReturnValue", "windows-registry"]
|
||||
- ["Microsoft.Win32.RegistryKey", "Method[GetValue].ReturnValue", "windows-registry"]
|
||||
- ["Microsoft.Win32.RegistryKey", "Method[GetValueNames].ReturnValue", "windows-registry"]
|
||||
- ["Microsoft.Win32.RegistryKey", "Method[GetSubKeyNames].ReturnValue", "windows-registry"]
|
||||
@@ -3,7 +3,7 @@ extensions:
|
||||
pack: microsoft-sdl/powershell-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["System.Environment", "Method[ExpandEnvironmentVariables].ReturnValue", "environment"]
|
||||
- ["System.Environment", "Method[GetCommandLineArgs].ReturnValue", "commandargs"]
|
||||
- ["System.Environment", "Method[GetEnvironmentVariable].ReturnValue", "environment"]
|
||||
- ["System.Environment", "Method[GetEnvironmentVariables].ReturnValue", "environment"]
|
||||
- ["System.Environment!", "Method[ExpandEnvironmentVariables].ReturnValue", "environment"]
|
||||
- ["System.Environment!", "Method[GetCommandLineArgs].ReturnValue", "commandargs"]
|
||||
- ["System.Environment!", "Method[GetEnvironmentVariable].ReturnValue", "environment"]
|
||||
- ["System.Environment!", "Method[GetEnvironmentVariables].ReturnValue", "environment"]
|
||||
@@ -3,19 +3,19 @@ extensions:
|
||||
pack: microsoft-sdl/powershell-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["System.IO.File", "Method[AppendText].ReturnValue", "file-write"]
|
||||
- ["System.IO.File", "Method[Create].ReturnValue", "file-write"]
|
||||
- ["System.IO.File", "Method[CreateText].ReturnValue", "file-write"]
|
||||
- ["System.IO.File", "Method[Open].ReturnValue", "file-write"]
|
||||
- ["System.IO.File", "Method[Open].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[OpenRead].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[OpenText].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[OpenWrite].ReturnValue", "file-write"]
|
||||
- ["System.IO.File", "Method[ReadAllBytes].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[ReadAllBytesAsync].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[ReadAllLines].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[ReadAllLinesAsync].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[ReadAllText].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[ReadAllTextAsync].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[ReadLines].ReturnValue", "file"]
|
||||
- ["System.IO.File", "Method[ReadLinesAsync].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[AppendText].ReturnValue", "file-write"]
|
||||
- ["System.IO.File!", "Method[Create].ReturnValue", "file-write"]
|
||||
- ["System.IO.File!", "Method[CreateText].ReturnValue", "file-write"]
|
||||
- ["System.IO.File!", "Method[Open].ReturnValue", "file-write"]
|
||||
- ["System.IO.File!", "Method[Open].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[OpenRead].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[OpenText].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[OpenWrite].ReturnValue", "file-write"]
|
||||
- ["System.IO.File!", "Method[ReadAllBytes].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[ReadAllBytesAsync].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[ReadAllLines].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[ReadAllLinesAsync].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[ReadAllText].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[ReadAllTextAsync].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[ReadLines].ReturnValue", "file"]
|
||||
- ["System.IO.File!", "Method[ReadLinesAsync].ReturnValue", "file"]
|
||||
@@ -3,11 +3,11 @@ extensions:
|
||||
pack: microsoft-sdl/powershell-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["System.IO.FileInfo", "Method[AppendText].ReturnValue", "file-write"]
|
||||
- ["System.IO.FileInfo", "Method[Create].ReturnValue", "file-write"]
|
||||
- ["System.IO.FileInfo", "Method[CreateText].ReturnValue", "file-write"]
|
||||
- ["System.IO.FileInfo", "Method[Open].ReturnValue", "file-write"]
|
||||
- ["System.IO.FileInfo", "Method[Open].ReturnValue", "file"]
|
||||
- ["System.IO.FileInfo", "Method[OpenRead].ReturnValue", "file"]
|
||||
- ["System.IO.FileInfo", "Method[OpenText].ReturnValue", "file"]
|
||||
- ["System.IO.FileInfo", "Method[OpenWrite].ReturnValue", "file-write"]
|
||||
- ["System.IO.FileInfo!", "Method[AppendText].ReturnValue", "file-write"]
|
||||
- ["System.IO.FileInfo!", "Method[Create].ReturnValue", "file-write"]
|
||||
- ["System.IO.FileInfo!", "Method[CreateText].ReturnValue", "file-write"]
|
||||
- ["System.IO.FileInfo!", "Method[Open].ReturnValue", "file-write"]
|
||||
- ["System.IO.FileInfo!", "Method[Open].ReturnValue", "file"]
|
||||
- ["System.IO.FileInfo!", "Method[OpenRead].ReturnValue", "file"]
|
||||
- ["System.IO.FileInfo!", "Method[OpenText].ReturnValue", "file"]
|
||||
- ["System.IO.FileInfo!", "Method[OpenWrite].ReturnValue", "file-write"]
|
||||
|
||||
@@ -32,11 +32,11 @@ bindingset[rawType]
|
||||
predicate isTypeUsed(string rawType) { any() }
|
||||
|
||||
bindingset[rawType]
|
||||
private predicate parseType(string rawType, string mod, string type) {
|
||||
private predicate parseType(string rawType, string consts, string suffix) {
|
||||
exists(string regexp |
|
||||
regexp = "(.+)\\.([^\\.]+)" and
|
||||
mod = rawType.regexpCapture(regexp, 1) and
|
||||
type = rawType.regexpCapture(regexp, 2)
|
||||
regexp = "([^!]+)(!|)" and
|
||||
consts = rawType.regexpCapture(regexp, 1) and
|
||||
suffix = rawType.regexpCapture(regexp, 2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -50,7 +50,31 @@ private predicate parseRelevantType(string rawType, string consts, string suffix
|
||||
* language semantics modeled by `getExtraNodeFromType`.
|
||||
*/
|
||||
bindingset[otherType]
|
||||
predicate hasImplicitTypeModel(string type, string otherType) { none() }
|
||||
predicate hasImplicitTypeModel(string type, string otherType) {
|
||||
// A::B! can be used to obtain A::B
|
||||
parseType(otherType, type, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
string getConstComponent(string consts, int n) {
|
||||
parseRelevantType(_, consts, _) and
|
||||
result = consts.splitAt(".", n)
|
||||
}
|
||||
|
||||
private int getNumConstComponents(string consts) {
|
||||
result = strictcount(int n | exists(getConstComponent(consts, n)))
|
||||
}
|
||||
|
||||
private DataFlow::TypePathNode getConstantFromConstPath(string consts, int n) {
|
||||
n = 1 and
|
||||
result.getComponent() = getConstComponent(consts, 0)
|
||||
or
|
||||
result = getConstantFromConstPath(consts, n - 1).getConstant(getConstComponent(consts, n - 1))
|
||||
}
|
||||
|
||||
private DataFlow::TypePathNode getConstantFromConstPath(string consts) {
|
||||
result = getConstantFromConstPath(consts, getNumConstComponents(consts))
|
||||
}
|
||||
|
||||
/** Gets a Powershell-specific interpretation of the `(type, path)` tuple after resolving the first `n` access path tokens. */
|
||||
bindingset[type, path]
|
||||
@@ -66,18 +90,20 @@ API::Node getExtraNodeFromPath(string type, AccessPath path, int n) {
|
||||
}
|
||||
|
||||
/** Gets a Powershell-specific interpretation of the given `type`. */
|
||||
API::Node getExtraNodeFromType(string qualifiedType) {
|
||||
qualifiedType = "" and
|
||||
result = API::root()
|
||||
or
|
||||
// TODO: How to distinguish between these cases? And do we need to?
|
||||
exists(string mod, string type | parseRelevantType(qualifiedType, mod, type) |
|
||||
result = API::mod(qualifiedType)
|
||||
API::Node getExtraNodeFromType(string type) {
|
||||
exists(string consts, string suffix, DataFlow::TypePathNode constRef |
|
||||
parseRelevantType(type, consts, suffix) and
|
||||
constRef = getConstantFromConstPath(consts)
|
||||
|
|
||||
suffix = "!" and
|
||||
result = constRef.track()
|
||||
or
|
||||
result = API::mod(qualifiedType).getInstance()
|
||||
or
|
||||
result = API::mod(mod).getType(type)
|
||||
suffix = "" and
|
||||
result = constRef.track().getInstance()
|
||||
)
|
||||
or
|
||||
type = "" and
|
||||
result = API::root()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user