diff --git a/powershell/ql/lib/semmle/code/powershell/Call.qll b/powershell/ql/lib/semmle/code/powershell/Call.qll index 53200c1ce0a..ae117801854 100644 --- a/powershell/ql/lib/semmle/code/powershell/Call.qll +++ b/powershell/ql/lib/semmle/code/powershell/Call.qll @@ -7,6 +7,8 @@ abstract private class AbstractCall extends Ast { Expr getNamedArgument(string name) { none() } + Expr getAnArgument() { result = this.getArgument(_) or result = this.getNamedArgument(_) } + Expr getQualifier() { none() } } diff --git a/powershell/ql/lib/semmle/code/powershell/Command.qll b/powershell/ql/lib/semmle/code/powershell/Command.qll index 694162f2808..a81e6c2686c 100644 --- a/powershell/ql/lib/semmle/code/powershell/Command.qll +++ b/powershell/ql/lib/semmle/code/powershell/Command.qll @@ -1,11 +1,11 @@ import powershell class Cmd extends @command, CmdBase { - override string toString() { result = this.getName() } + override string toString() { result = this.getCommandName() } override SourceLocation getLocation() { command_location(this, result) } - string getName() { command(this, result, _, _, _) } + string getCommandName() { command(this, result, _, _, _) } int getKind() { command(this, _, result, _, _) } @@ -19,6 +19,8 @@ class Cmd extends @command, CmdBase { StringConstExpr getCmdName() { result = this.getElement(0) } + Expr getAnArgument() { result = this.getArgument(_) or result = this.getNamedArgument(_) } + Expr getArgument(int i) { result = rank[i + 1](CmdElement e, int j | diff --git a/powershell/ql/lib/semmle/code/powershell/CommentEntity.qll b/powershell/ql/lib/semmle/code/powershell/CommentEntity.qll index cd46c8cb83f..d234eb0f3c7 100644 --- a/powershell/ql/lib/semmle/code/powershell/CommentEntity.qll +++ b/powershell/ql/lib/semmle/code/powershell/CommentEntity.qll @@ -1,9 +1,17 @@ import powershell class Comment extends @comment_entity { - SourceLocation getLocation() { comment_entity_location(this, result) } + Location getLocation() { comment_entity_location(this, result) } StringLiteral getCommentContents() { comment_entity(this, result) } - string toString() { result = "Comment at: " + this.getLocation().toString() } + string toString() { result = this.getCommentContents().toString() } +} + +class SingleLineComment extends Comment { + SingleLineComment() { this.getCommentContents().getNumContinuations() = 1 } +} + +class MultiLineComment extends Comment { + MultiLineComment() { this.getCommentContents().getNumContinuations() > 1 } } diff --git a/powershell/ql/lib/semmle/code/powershell/StringLiteral.qll b/powershell/ql/lib/semmle/code/powershell/StringLiteral.qll index 77ece5d7d1c..a7f85ece8e4 100644 --- a/powershell/ql/lib/semmle/code/powershell/StringLiteral.qll +++ b/powershell/ql/lib/semmle/code/powershell/StringLiteral.qll @@ -1,14 +1,12 @@ import powershell class StringLiteral extends @string_literal { - int getNumContinuations() { string_literal_line(this, result, _) } + int getNumContinuations() { result = strictcount(int i | exists(this.getContinuation(i))) } string getContinuation(int index) { string_literal_line(this, index, result) } /** Get the full string literal with all its parts concatenated */ - string toString() { - result = this.getValue() - } + string toString() { result = this.getValue() } string getValue() { result = concat(int i | i = [0 .. this.getNumContinuations()] | this.getContinuation(i), "\n") diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll index ac51896d0c4..d37d566ea0d 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll @@ -23,7 +23,7 @@ private newtype TCompletion = private predicate commandThrows(Cmd c, boolean unconditional) { c.getNamedArgument("ErrorAction").(StringConstExpr).getValue().getValue() = "Stop" and - if c.getName() = "Write-Error" then unconditional = true else unconditional = false + if c.getCommandName() = "Write-Error" then unconditional = true else unconditional = false } pragma[noinline] diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll index 9bc578a6c7a..9da8705332e 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll @@ -41,6 +41,14 @@ private class ExprNodeImpl extends ExprNode, NodeImpl { override string toStringImpl() { result = this.getExprNode().toString() } } +private class StmtNodeImpl extends StmtNode, NodeImpl { + override CfgScope getCfgScope() { none() /* TODO */ } + + override Location getLocationImpl() { result = this.getStmtNode().getLocation() } + + override string toStringImpl() { result = this.getStmtNode().toString() } +} + /** Gets the SSA definition node corresponding to parameter `p`. */ pragma[nomagic] SsaImpl::DefinitionExt getParameterDef(Parameter p) { @@ -61,7 +69,7 @@ module SsaFlow { Impl::Node asNode(Node n) { n = TSsaNode(result) or - result.(Impl::ExprNode).getExpr() = n.asExpr() + result.(Impl::ExprNode).getExpr() = n.asExpr() // TODO: Statement nodes? or result.(Impl::ExprPostUpdateNode).getExpr() = n.(PostUpdateNode).getPreUpdateNode().asExpr() or @@ -98,6 +106,7 @@ private module Cached { cached newtype TNode = TExprNode(CfgNodes::ExprCfgNode n) or + TStmtNode(CfgNodes::StmtCfgNode n) or TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or TNormalParameterNode(Parameter p) or TExprPostUpdateNode(CfgNodes::ExprCfgNode n) { diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll index 1e91f1ea844..e197a4e5edf 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll @@ -11,6 +11,8 @@ class Node extends TNode { /** Gets the expression corresponding to this node, if any. */ CfgNodes::ExprCfgNode asExpr() { result = this.(ExprNode).getExprNode() } + CfgNodes::StmtCfgNode asStmt() { result = this.(StmtNode).getStmtNode() } + /** Gets the parameter corresponding to this node, if any. */ Parameter asParameter() { result = this.(ParameterNode).getParameter() } @@ -47,6 +49,22 @@ class ExprNode extends Node, TExprNode { CfgNodes::ExprCfgNode getExprNode() { result = n } } +/** + * A statement, viewed as a node in a data flow graph. + * + * Note that because of control-flow splitting, one `Stmt` may correspond + * to multiple `StmtNode`s, just like it may correspond to multiple + * `ControlFlow::Node`s. + */ +class StmtNode extends Node, TStmtNode { + private CfgNodes::StmtCfgNode n; + + StmtNode() { this = TStmtNode(n) } + + /** Gets the expression corresponding to this node. */ + CfgNodes::StmtCfgNode getStmtNode() { result = n } +} + /** * The value of a parameter at function entry, viewed as a node in a data * flow graph. @@ -103,6 +121,9 @@ private import Cached /** Gets a node corresponding to expression `e`. */ ExprNode exprNode(CfgNodes::ExprCfgNode e) { result.getExprNode() = e } +/** Gets a node corresponding to statement `s`. */ +StmtNode stmtNode(CfgNodes::StmtCfgNode e) { result.getStmtNode() = e } + /** * Gets the node corresponding to the value of parameter `p` at function entry. */ diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingImplSpecific.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingImplSpecific.qll index a0a221ac169..ad7e6716094 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingImplSpecific.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingImplSpecific.qll @@ -2,7 +2,7 @@ * Provides Powershell-specific definitions for use in the taint tracking library. */ -private import codeql.Locations +private import powershell private import codeql.dataflow.TaintTracking private import DataFlowImplSpecific