diff --git a/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll b/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll index 455ebbb1a15..f233fb840cf 100644 --- a/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll +++ b/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll @@ -152,6 +152,16 @@ module API { pragma[inline_late] Node getReturn() { Impl::returnEdge(this.getAnEpsilonSuccessor(), result) } + /** + * Gets the result of this call when there is a named argument with the + * name `name`, or the return value of this callable. + */ + bindingset[this] + pragma[inline_late] + Node getReturnWithArg(string name) { + Impl::returnEdgeWithArg(this.getAnEpsilonSuccessor(), name, result) + } + /** * Gets the result of a call to `method` with this value as the receiver, or the return value of `method` defined on * an object that can reach this sink. @@ -695,6 +705,21 @@ module API { ) } + cached + predicate returnEdgeWithArg(Node pred, string arg, Node succ) { + exists(DataFlow::CallNode call | + pred = MkMethodAccessNode(call) and + exists(call.getNamedArgument(arg)) and + succ = getForwardStartNode(call) + ) + or + arg = "" and // TODO + exists(DataFlow::CallableNode callable | + pred = getBackwardEndNode(callable) and + succ = MkSinkNode(callable.getAReturnNode()) + ) + } + cached predicate entryPointEdge(EntryPoint entry, Node node) { node = MkSinkNode(entry.getASink()) or diff --git a/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModels.qll b/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModels.qll index aec65d1819c..fea1c3fe4bd 100644 --- a/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModels.qll +++ b/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModels.qll @@ -254,7 +254,12 @@ API::Node getSuccessorFromNode(API::Node node, AccessPathTokenBase token) { result = node.getParameter(parseIntUnbounded(token.getAnArgument())) or token.getName() = "ReturnValue" and - result = node.getReturn() + ( + not exists(token.getAnArgument()) and + result = node.getReturn() + or + result = node.getReturnWithArg(token.getAnArgument()) + ) or // Language-specific tokens result = Specific::getExtraSuccessorFromNode(node, token) @@ -269,7 +274,12 @@ API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathTokenBas result = invoke.getParameter(parseIntWithArity(token.getAnArgument(), invoke.getNumArgument())) or token.getName() = "ReturnValue" and - result = invoke.getReturn() + ( + not exists(token.getAnArgument()) and + result = invoke.getReturn() + or + result = invoke.getReturnWithArg(token.getAnArgument()) + ) or // Language-specific tokens result = Specific::getExtraSuccessorFromInvoke(invoke, token) 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 0dfb616d399..d97c3cd78c8 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 @@ -95,7 +95,7 @@ API::Node getExtraNodeFromType(string rawType) { result = qualifiedTypeName.(DataFlow::LocalSourceNode).track().getInstance() ) or - (rawType = ["", getAnImplicitImport()]) and + rawType = ["", getAnImplicitImport()] and result = API::root() }