PS: Support implicit imports in API graphs.

This commit is contained in:
Mathias Vorreiter Pedersen
2025-04-08 17:43:10 +01:00
parent a5afc3c582
commit 6de4765fe6
2 changed files with 56 additions and 11 deletions

View File

@@ -10,6 +10,8 @@ private import semmle.code.powershell.dataflow.DataFlow
private import semmle.code.powershell.typetracking.ApiGraphShared
private import semmle.code.powershell.typetracking.internal.TypeTrackingImpl
private import semmle.code.powershell.controlflow.Cfg
private import frameworks.data.internal.ApiGraphModelsExtensions as Extensions
private import frameworks.data.internal.ApiGraphModelsSpecific as Specific
private import semmle.code.powershell.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import semmle.code.powershell.dataflow.internal.DataFlowDispatch as DataFlowDispatch
@@ -514,12 +516,48 @@ module API {
)
}
bindingset[name]
private string memberOrMethodReturnValue(string name) {
// This predicate is a bit ad-hoc, but it's okay for now.
// We can delete it once we no longer use the typeModel and summaryModel
// tables to represent implicit root members.
result = "Method[" + name + "]"
or
result = "Method[" + name + "].ReturnValue"
or
result = "Member[" + name + "]"
}
private Node getAnImplicitRootMember(string name) {
exists(DataFlow::CallNode call |
Extensions::typeModel(_, Specific::getAnImplicitImport(), memberOrMethodReturnValue(name))
or
Extensions::summaryModel(Specific::getAnImplicitImport(), memberOrMethodReturnValue(name),
_, _, _, _)
or
Extensions::sourceModel(Specific::getAnImplicitImport(), memberOrMethodReturnValue(name), _,
_)
|
result = MkMethodAccessNode(call) and
name = call.getName().toLowerCase()
)
}
cached
predicate memberEdge(Node pred, string name, Node succ) {
exists(StringConstExpr read |
succ = getForwardStartNode(getNodeFromExpr(read)) and
pred = MkRoot() and
name = read.getValueString()
pred = API::root() and
(
exists(StringConstExpr read |
succ = getForwardStartNode(getNodeFromExpr(read)) and
name = read.getValueString()
)
or
exists(DataFlow::AutomaticVariableNode automatic |
automatic.getName() = name and
succ = getForwardStartNode(automatic)
)
or
succ = getAnImplicitRootMember(name)
)
or
exists(DataFlow::QualifiedTypeNameNode typeName |
@@ -528,12 +566,6 @@ module API {
succ = getForwardStartNode(typeName)
)
or
pred = MkRoot() and
exists(DataFlow::AutomaticVariableNode automatic |
automatic.getName() = name and
succ = getForwardStartNode(automatic)
)
or
exists(MemberExprReadAccess read |
read.getMemberName().toLowerCase() = name and
pred = getForwardEndNode(getALocalSourceStrict(getNodeFromExpr(read.getQualifier()))) and
@@ -548,6 +580,9 @@ module API {
|
pred = getForwardEndNode(getALocalSourceStrict(call.getQualifier()))
)
or
pred = API::root() and
succ = getAnImplicitRootMember(name)
}
cached

View File

@@ -68,6 +68,16 @@ API::Node getExtraNodeFromPath(string type, AccessPath path, int n) {
)
}
/**
* Gets a string that represents a module that is always implicitly
* imported in any powershell script.
*/
string getAnImplicitImport() {
result = "microsoft.powershell.management!"
or
result = "microsoft.powershell.utility!"
}
/** Gets a Powershell-specific interpretation of the given `type`. */
API::Node getExtraNodeFromType(string rawType) {
exists(
@@ -85,7 +95,7 @@ API::Node getExtraNodeFromType(string rawType) {
result = qualifiedTypeName.(DataFlow::LocalSourceNode).track().getInstance()
)
or
rawType = "" and
(rawType = ["", getAnImplicitImport()]) and
result = API::root()
}