diff --git a/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll b/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll index 78b84587908..455ebbb1a15 100644 --- a/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll +++ b/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll @@ -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 diff --git a/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll b/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll index 6e791858ce3..0dfb616d399 100644 --- a/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -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() }