From 820f4b2575abea5375be4e686d68a8389409cb38 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 4 Oct 2024 19:31:55 +0100 Subject: [PATCH 1/9] PS: Add tests with arrays. --- .../library-tests/dataflow/fields/test.ps1 | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 index a1e6277d3de..4e0dc1d33a8 100644 --- a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 +++ b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 @@ -4,3 +4,28 @@ Sink $a.f # $ hasValueFlow=1 $a.f = Source "2" $a.f = 0 Sink $a.f # clean + +$arr1[3] = Source "3" +Sink $arr1[3] # $ MISSING: hasValueFlow=3 +Sink $arr1[4] # clean + +$arr2[$unknown] = Source "4" +Sink $arr2[4] # $ MISSING: hasValueFlow=4 + +$arr3[3] = Source "5" +Sink $arr3[$unknown] # $ MISSING: hasValueFlow=5 + +$arr4[$unknown1] = Source "6" +Sink $arr4[$unknown2] # $ MISSING: hasValueFlow=6 + +$arr5[$unknown3][1] = Source "7" +Sink $arr5[$unknown3][1] # $ MISSING: hasValueFlow=7 +Sink $arr5[$unknown3][2] # clean + +$arr6[1][$unknown4] = Source "8" +Sink $arr6[1][$unknown4] # $ MISSING: hasValueFlow=8 +Sink $arr6[2][$unknown4] # clean + +$arr7[$unknown5][$unknown6] = Source "9" +Sink $arr7[1][2] # $ MISSING: hasValueFlow=9 +Sink $arr7[$unknown7][$unknown8] # $ MISSING: hasValueFlow=9 \ No newline at end of file From 22e508b85bece3c7952b06f5aaa80710db442770 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 4 Oct 2024 19:13:51 +0100 Subject: [PATCH 2/9] PS: Introduce a class for constant values. --- .../code/powershell/ConstantExpression.qll | 116 ++++++++++++++++++ .../lib/semmle/code/powershell/Expression.qll | 10 +- .../code/powershell/controlflow/CfgNodes.qll | 2 + 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll index 9d0e6f23980..11c9b3a4caf 100644 --- a/powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll @@ -9,3 +9,119 @@ class ConstExpr extends @constant_expression, BaseConstExpr { override string toString() { result = this.getValue().toString() } } + +private newtype TConstantValue = + TConstInteger(int value) { + exists(ConstExpr ce | ce.getType() = "Int32" and ce.getValue().getValue().toInt() = value) + } or + TConstDouble(float double) { + exists(ConstExpr ce | ce.getType() = "Double" and ce.getValue().getValue().toFloat() = double) + } or + TConstString(string value) { exists(StringLiteral sl | sl.getValue() = value) } or + TConstBoolean(boolean value) { + exists(VarAccess va | + value = true and + va.getUserPath() = "true" + or + value = false and + va.getUserPath() = "false" + ) + } or + TNull() + +/** A constant value. */ +class ConstantValue extends TConstantValue { + /** Gets a string representation of this value. */ + final string toString() { result = this.getValue() } + + /** Gets the value of this consant. */ + string getValue() { none() } + + /** Gets the integer value of this constant, if any. */ + int asInt() { none() } + + /** Gets the floating point value of this constant, if any. */ + float asDouble() { none() } + + /** Gets the string value of this constant, if any. */ + string asString() { none() } + + /** Gets the boolean value of this constant, if any. */ + boolean asBoolean() { none() } + + /** Holds if this constant represents the null value. */ + predicate isNull() { none() } + + /** Gets a (unique) serialized version of this value. */ + string serialize() { none() } + + /** Gets an exprssion that has this value. */ + Expr getAnExpr() { none() } +} + +/** A constant integer value */ +class ConstInteger extends ConstantValue, TConstInteger { + final override int asInt() { this = TConstInteger(result) } + + final override string getValue() { result = this.asInt().toString() } + + final override string serialize() { result = this.getValue() } + + final override ConstExpr getAnExpr() { result.getValue().getValue() = this.getValue() } +} + +/** A constant floating point value. */ +class ConstDouble extends ConstantValue, TConstDouble { + final override float asDouble() { this = TConstDouble(result) } + + final override string getValue() { result = this.asDouble().toString() } + + final override string serialize() { + exists(string res | res = this.asDouble().toString() | + if exists(res.indexOf(".")) then result = res else result = res + ".0" + ) + } + + final override ConstExpr getAnExpr() { result.getValue().getValue() = this.getValue() } +} + +/** A constant string value. */ +class ConstString extends ConstantValue, TConstString { + final override string asString() { this = TConstString(result) } + + final override string getValue() { result = this.asString() } + + final override string serialize() { + result = "\"" + this.asString().replaceAll("\"", "\\\"") + "\"" + } + + final override ConstExpr getAnExpr() { result.getValue().getValue() = this.getValue() } +} + +/** A constant boolean value. */ +class ConstBoolean extends ConstantValue, TConstBoolean { + final override boolean asBoolean() { this = TConstBoolean(result) } + + final override string getValue() { result = this.asBoolean().toString() } + + final override string serialize() { result = this.getValue() } + + final override VarAccess getAnExpr() { + this.asBoolean() = true and + result.getUserPath() = "true" + or + this.asBoolean() = false and + result.getUserPath() = "false" + } +} + +/** The constant null value. */ +class NullConst extends ConstantValue, TNull { + final override predicate isNull() { any() } + + final override string getValue() { result = "null" } + + final override string serialize() { result = this.getValue() } + + final override VarAccess getAnExpr() { result.getUserPath() = "null" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/Expression.qll b/powershell/ql/lib/semmle/code/powershell/Expression.qll index 97df75538c0..909c971f6e6 100644 --- a/powershell/ql/lib/semmle/code/powershell/Expression.qll +++ b/powershell/ql/lib/semmle/code/powershell/Expression.qll @@ -1,3 +1,11 @@ import powershell -class Expr extends @expression, CmdElement { } +/** + * An expression. + * + * This is the topmost class in the hierachy of all expression in PowerShell. + */ +class Expr extends @expression, CmdElement { + /** Gets the constant value of this expression, if this is known. */ + final ConstantValue getValue() { result.getAnExpr() = this } +} diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index 642c03c5414..ad8c3909bed 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -46,6 +46,8 @@ class ExprCfgNode extends AstCfgNode { /** Gets the underlying expression. */ Expr getExpr() { result = e } + + final ConstantValue getValue() { result = e.getValue() } } /** A control-flow node that wraps an AST statement. */ From 28b654df466e241b30dc35cb6bafb2a6f27843e6 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 4 Oct 2024 19:16:14 +0100 Subject: [PATCH 3/9] PS: Add helper clases for index expression. --- .../lib/semmle/code/powershell/IndexExpr.qll | 17 +++++++++++ .../code/powershell/VariableExpression.qll | 13 ++------- .../code/powershell/controlflow/CfgNodes.qll | 29 +++++++++++++++++++ .../powershell/internal/ExplicitWrite.qll | 15 ++++++++++ .../code/powershell/internal/Internal.qll | 3 +- 5 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 powershell/ql/lib/semmle/code/powershell/internal/ExplicitWrite.qll diff --git a/powershell/ql/lib/semmle/code/powershell/IndexExpr.qll b/powershell/ql/lib/semmle/code/powershell/IndexExpr.qll index e18d21edb04..8e69928be5e 100644 --- a/powershell/ql/lib/semmle/code/powershell/IndexExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/IndexExpr.qll @@ -1,4 +1,5 @@ import powershell +private import internal.ExplicitWrite class IndexExpr extends @index_expression, Expr { override string toString() { result = "...[...]" } @@ -11,3 +12,19 @@ class IndexExpr extends @index_expression, Expr { predicate isNullConditional() { index_expression(this, _, _, true) } } + +private predicate isImplicitIndexWrite(Expr e) { none() } + +/** An index expression that is being written to. */ +class IndexExprWrite extends IndexExpr { + IndexExprWrite() { isExplicitWrite(this, _) or isImplicitIndexWrite(this) } + + predicate isExplicit(AssignStmt assign) { isExplicitWrite(this, assign) } + + predicate isImplicit() { isImplicitIndexWrite(this) } +} + +/** An index expression that is being read from. */ +class IndexExprRead extends IndexExpr { + IndexExprRead() { not this instanceof IndexExprWrite } +} diff --git a/powershell/ql/lib/semmle/code/powershell/VariableExpression.qll b/powershell/ql/lib/semmle/code/powershell/VariableExpression.qll index fa2be0b4e75..517cffd3efa 100644 --- a/powershell/ql/lib/semmle/code/powershell/VariableExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/VariableExpression.qll @@ -1,4 +1,5 @@ import powershell +private import internal.ExplicitWrite private predicate isParameterName(@variable_expression ve) { parameter(_, ve, _, _) } @@ -34,14 +35,6 @@ class VarAccess extends @variable_expression, Expr { Variable getVariable() { result.getAnAccess() = this } } -private predicate isExplicitVariableWriteAccess(Expr e, AssignStmt assign) { - e = assign.getLeftHandSide() - or - e = any(ConvertExpr convert | isExplicitVariableWriteAccess(convert, assign)).getExpr() - or - e = any(ArrayLiteral array | isExplicitVariableWriteAccess(array, assign)).getAnElement() -} - private predicate isImplicitVariableWriteAccess(Expr e) { none() } class VarReadAccess extends VarAccess { @@ -49,9 +42,9 @@ class VarReadAccess extends VarAccess { } class VarWriteAccess extends VarAccess { - VarWriteAccess() { isExplicitVariableWriteAccess(this, _) or isImplicitVariableWriteAccess(this) } + VarWriteAccess() { isExplicitWrite(this, _) or isImplicitVariableWriteAccess(this) } - predicate isExplicit(AssignStmt assign) { isExplicitVariableWriteAccess(this, assign) } + predicate isExplicit(AssignStmt assign) { isExplicitWrite(this, assign) } predicate isImplicit() { isImplicitVariableWriteAccess(this) } } diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index ad8c3909bed..7db4c1d2996 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -325,12 +325,41 @@ module ExprNodes { /** A control-flow node that wraps a `MemberExpr` expression that is being written to. */ class MemberCfgWriteAccessNode extends MemberCfgNode { MemberCfgWriteAccessNode() { this.getExpr() instanceof MemberExprWriteAccess } + + StmtNodes::AssignStmtCfgNode getAssignStmt() { result.getLeftHandSide() = this } } /** A control-flow node that wraps a `MemberExpr` expression that is being read from. */ class MemberCfgReadAccessNode extends MemberCfgNode { MemberCfgReadAccessNode() { this.getExpr() instanceof MemberExprReadAccess } } + + class IndexChildMapping extends ExprChildMapping, IndexExpr { + override predicate relevantChild(Ast n) { n = this.getBase() or n = this.getIndex() } + } + + /** A control-flow node that wraps a `MemberExpr` expression. */ + class IndexCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "IndexCfgNode" } + + override IndexChildMapping e; + + final ExprCfgNode getBase() { e.hasCfgChild(e.getBase(), this, result) } + + final ExprCfgNode getIndex() { e.hasCfgChild(e.getIndex(), this, result) } + } + + /** A control-flow node that wraps a `MemberExpr` expression that is being written to. */ + class IndexCfgWriteNode extends IndexCfgNode { + IndexCfgWriteNode() { this.getExpr() instanceof IndexExprWrite } + + StmtNodes::AssignStmtCfgNode getAssignStmt() { result.getLeftHandSide() = this } + } + + /** A control-flow node that wraps a `MemberExpr` expression that is being read from. */ + class IndexCfgReadNode extends IndexCfgNode { + IndexCfgReadNode() { this.getExpr() instanceof IndexExprRead } + } } module StmtNodes { diff --git a/powershell/ql/lib/semmle/code/powershell/internal/ExplicitWrite.qll b/powershell/ql/lib/semmle/code/powershell/internal/ExplicitWrite.qll new file mode 100644 index 00000000000..210a6213420 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/internal/ExplicitWrite.qll @@ -0,0 +1,15 @@ +private import powershell + +/** + * Holds if `e` is written to by `assign`. + * + * Note there may be more than one `e` for which `isExplicitWrite(e, assign)` + * holds if the left-hand side is an array literal. + */ +predicate isExplicitWrite(Expr e, AssignStmt assign) { + e = assign.getLeftHandSide() + or + e = any(ConvertExpr convert | isExplicitWrite(convert, assign)).getExpr() + or + e = any(ArrayLiteral array | isExplicitWrite(array, assign)).getAnElement() +} diff --git a/powershell/ql/lib/semmle/code/powershell/internal/Internal.qll b/powershell/ql/lib/semmle/code/powershell/internal/Internal.qll index be00f67e560..92beec81a9d 100644 --- a/powershell/ql/lib/semmle/code/powershell/internal/Internal.qll +++ b/powershell/ql/lib/semmle/code/powershell/internal/Internal.qll @@ -1 +1,2 @@ -import Parameter \ No newline at end of file +import Parameter +import ExplicitWrite \ No newline at end of file From 1f558a0b7f267a8fd46255a9b297d155545b6b24 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 4 Oct 2024 19:16:50 +0100 Subject: [PATCH 4/9] PS: Add CFG classes for array literals. --- .../code/powershell/controlflow/CfgNodes.qll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index 7db4c1d2996..e5f6185702a 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -334,6 +334,20 @@ module ExprNodes { MemberCfgReadAccessNode() { this.getExpr() instanceof MemberExprReadAccess } } + class ArrayLiteralChildMapping extends ExprChildMapping, ArrayLiteral { + override predicate relevantChild(Ast n) { n = this.getAnElement() } + } + + class ArrayLiteralCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ArrayLiteralCfgNode" } + + override ArrayLiteralChildMapping e; + + ExprCfgNode getElement(int i) { e.hasCfgChild(e.getElement(i), this, result) } + + ExprCfgNode getAnElement() { e.hasCfgChild(e.getAnElement(), this, result) } + } + class IndexChildMapping extends ExprChildMapping, IndexExpr { override predicate relevantChild(Ast n) { n = this.getBase() or n = this.getIndex() } } From cbfd0b363b6f0d7db491b239f768d0dd6e356ac2 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 4 Oct 2024 19:18:52 +0100 Subject: [PATCH 5/9] PS: Add element content flow for reads and writes into arrays. --- .../dataflow/internal/DataFlowPrivate.qll | 107 ++++++++++++++---- .../dataflow/internal/DataFlowPublic.qll | 73 +++++++++++- .../internal/TaintTrackingPrivate.qll | 14 ++- .../internal/TypeTrackingImpl.qll | 14 ++- 4 files changed, 183 insertions(+), 25 deletions(-) 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 5a2e3f1145b..815df034a5a 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll @@ -128,6 +128,8 @@ private module Cached { n = member.getBase() and not member.isStatic() ) + or + n = any(CfgNodes::ExprNodes::IndexCfgNode index).getBase() } cached @@ -219,7 +221,16 @@ private module Cached { } cached - newtype TContentSet = TSingletonContent(Content c) + newtype TContentSet = + TSingletonContent(Content c) or + TAnyElementContent() or + TKnownOrUnknownElementContent(Content::KnownElementContent c) + + private predicate trackKnownValue(ConstantValue cv) { + exists(cv.asString()) + or + cv.asInt() = [0 .. 10] + } cached newtype TContent = @@ -227,15 +238,34 @@ private module Cached { name = any(PropertyMember member).getName() or name = any(MemberExpr me).getMemberName() - } + } or + TKnownElementContent(ConstantValue cv) { trackKnownValue(cv) } or + TUnknownElementContent() cached - newtype TContentApprox = TNonElementContentApprox(Content c) + newtype TContentApprox = + TNonElementContentApprox(Content c) { not c instanceof Content::ElementContent } or + TUnknownElementContentApprox() or + TKnownIntegerElementContentApprox() or + TKnownElementContentApprox(string approx) { approx = approxKnownElementIndex(_) } cached newtype TDataFlowType = TUnknownDataFlowType() } +class TElementContent = TKnownElementContent or TUnknownElementContent; + +/** Gets a string for approximating known element indices. */ +private string approxKnownElementIndex(ConstantValue cv) { + not exists(cv.asInt()) and + exists(string s | s = cv.serialize() | + s.length() < 2 and + result = s + or + result = s.prefix(2) + ) +} + import Cached /** Holds if `n` should be hidden from path explanations. */ @@ -477,26 +507,54 @@ predicate jumpStep(Node pred, Node succ) { * content `c`. */ predicate storeStep(Node node1, ContentSet c, Node node2) { - node2.(PostUpdateNode).getPreUpdateNode().asExpr() = - any(CfgNodes::ExprNodes::MemberCfgNode var | - exists(CfgNodes::StmtNodes::AssignStmtCfgNode assign | - var = assign.getLeftHandSide() and - node1.asStmt() = assign.getRightHandSide() - | - c.isSingleton(any(Content::FieldContent ct | ct.getName() = var.getMemberName())) - ) - ).getBase() + exists(CfgNodes::ExprNodes::MemberCfgWriteAccessNode var, Content::FieldContent fc | + node2.(PostUpdateNode).getPreUpdateNode().asExpr() = var.getBase() and + node1.asStmt() = var.getAssignStmt().getRightHandSide() and + fc.getName() = var.getMemberName() and + c.isSingleton(fc) + ) + or + exists( + CfgNodes::ExprNodes::IndexCfgWriteNode var, Content::KnownElementContent ec, int index, + CfgNodes::ExprCfgNode e + | + node2.(PostUpdateNode).getPreUpdateNode().asExpr() = var.getBase() and + node1.asStmt() = var.getAssignStmt().getRightHandSide() and + c.isKnownOrUnknownElement(ec) and + index = ec.getIndex().asInt() and + e = var.getIndex() + | + index = e.getValue().asInt() + or + not exists(e.getValue().asInt()) + ) } /** * Holds if there is a read step of content `c` from `node1` to `node2`. */ predicate readStep(Node node1, ContentSet c, Node node2) { - node2.asExpr() = - any(CfgNodes::ExprNodes::MemberCfgReadAccessNode var | - node1.asExpr() = var.getBase() and - c.isSingleton(any(Content::FieldContent ct | ct.getName() = var.getMemberName())) - ) + exists(CfgNodes::ExprNodes::MemberCfgReadAccessNode var, Content::FieldContent fc | + node2.asExpr() = var and + node1.asExpr() = var.getBase() and + fc.getName() = var.getMemberName() and + c.isSingleton(fc) + ) + or + exists( + CfgNodes::ExprNodes::IndexCfgReadNode var, Content::KnownElementContent ec, int index, + CfgNodes::ExprCfgNode e + | + node2.asExpr() = var and + node1.asExpr() = var.getBase() and + c.isKnownOrUnknownElement(ec) and + index = ec.getIndex().asInt() and + e = var.getIndex() + | + index = e.getValue().asInt() + or + not exists(e.getValue().asInt()) + ) } /** @@ -584,7 +642,7 @@ class DataFlowExpr = CfgNodes::ExprCfgNode; * Holds if access paths with `c` at their head always should be tracked at high * precision. This disables adaptive access path precision for such access paths. */ -predicate forceHighPrecision(Content c) { none() } +predicate forceHighPrecision(Content c) { c instanceof Content::ElementContent } class NodeRegion instanceof Unit { string toString() { result = "NodeRegion" } @@ -653,7 +711,18 @@ class ContentApprox extends TContentApprox { } /** Gets an approximated value for content `c`. */ -ContentApprox getContentApprox(Content c) { result = TNonElementContentApprox(c) } +ContentApprox getContentApprox(Content c) { + c instanceof Content::UnknownElementContent and + result = TUnknownElementContentApprox() + or + exists(c.(Content::KnownElementContent).getIndex().asInt()) and + result = TKnownIntegerElementContentApprox() + or + result = + TKnownElementContentApprox(approxKnownElementIndex(c.(Content::KnownElementContent).getIndex())) + or + result = TNonElementContentApprox(c) +} /** * A unit class for adding additional jump steps. 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 5dd19b1eabe..03ceb54bfd2 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll @@ -169,6 +169,26 @@ class Content extends TContent { /** Provides different sub classes of `Content`. */ module Content { + /** An element in a collection, for example an element in an array or in a hash. */ + class ElementContent extends Content, TElementContent { } + + /** An element in a collection at a known index. */ + class KnownElementContent extends ElementContent, TKnownElementContent { + private ConstantValue cv; + + KnownElementContent() { this = TKnownElementContent(cv) } + + /** Gets the index in the collection. */ + ConstantValue getIndex() { result = cv } + + override string toString() { result = "element " + cv } + } + + /** An element in a collection at an unknown index. */ + class UnknownElementContent extends ElementContent, TUnknownElementContent { + override string toString() { result = "element" } + } + /** A field of an object. */ class FieldContent extends Content, TFieldContent { private string name; @@ -192,19 +212,66 @@ class ContentSet extends TContentSet { /** Holds if this content set is the singleton `{c}`. */ predicate isSingleton(Content c) { this = TSingletonContent(c) } + /** Holds if this content set represents all `ElementContent`s. */ + predicate isAnyElement() { this = TAnyElementContent() } + + /** + * Holds if this content set represents a specific known element index, or an + * unknown element index. + */ + predicate isKnownOrUnknownElement(Content::KnownElementContent c) { + this = TKnownOrUnknownElementContent(c) + } + /** Gets a textual representation of this content set. */ string toString() { exists(Content c | this.isSingleton(c) and result = c.toString() ) + or + this.isAnyElement() and + result = "any element" + or + exists(Content::KnownElementContent c | + this.isKnownOrUnknownElement(c) and + result = c + " or unknown" + ) } - /** Gets a content that may be stored into when storing into this set. */ - Content getAStoreContent() { this.isSingleton(result) } + Content getAStoreContent() { + this.isSingleton(result) + or + // For reverse stores, `a[unknown][0] = x`, it is important that the read-step + // from `a` to `a[unknown]` (which can read any element), gets translated into + // a reverse store step that store only into `?` + this.isAnyElement() and + result = TUnknownElementContent() + or + // For reverse stores, `a[1][0] = x`, it is important that the read-step + // from `a` to `a[1]` (which can read both elements stored at exactly index `1` + // and elements stored at unknown index), gets translated into a reverse store + // step that store only into `1` + this.isKnownOrUnknownElement(result) + } + + pragma[nomagic] + private Content getAnElementReadContent() { + exists(Content::KnownElementContent c | this.isKnownOrUnknownElement(c) | + result = c or + result = TUnknownElementContent() + ) + } /** Gets a content that may be read from when reading from this set. */ - Content getAReadContent() { this.isSingleton(result) } + Content getAReadContent() { + this.isSingleton(result) + or + this.isAnyElement() and + result instanceof Content::ElementContent + or + result = this.getAnElementReadContent() + } } /** diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll index 08f53d78bc1..ac6a32de36d 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll @@ -30,7 +30,19 @@ private module Cached { */ cached predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) { - none() + // Although flow through collections is modeled precisely using stores/reads, we still + // allow flow out of a _tainted_ collection. This is needed in order to support taint- + // tracking configurations where the source is a collection. + exists(DataFlow::ContentSet c | readStep(nodeFrom, c, nodeTo) | + c.isSingleton(any(DataFlow::Content::ElementContent ec)) + or + c.isKnownOrUnknownElement(_) + // or + // TODO: We do't generate this one from readSteps yet, but we will as + // soon as we start on models-as-data. + // c.isAnyElement() + ) and + model = "" } /** diff --git a/powershell/ql/lib/semmle/code/powershell/typetracking/internal/TypeTrackingImpl.qll b/powershell/ql/lib/semmle/code/powershell/typetracking/internal/TypeTrackingImpl.qll index b806c9400f2..e2d21739a57 100644 --- a/powershell/ql/lib/semmle/code/powershell/typetracking/internal/TypeTrackingImpl.qll +++ b/powershell/ql/lib/semmle/code/powershell/typetracking/internal/TypeTrackingImpl.qll @@ -53,11 +53,21 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { class ContentFilter = TypeTrackingInput::ContentFilter; ContentFilter getFilterFromWithoutContentStep(Content content) { - none() // TODO + ( + content.isAnyElement() + or + content.isSingleton(any(DataFlow::Content::UnknownElementContent c)) + ) and + result = MkElementFilter() } ContentFilter getFilterFromWithContentStep(Content content) { - none() // TODO + ( + content.isAnyElement() + or + content.isSingleton(any(DataFlow::Content::ElementContent c)) + ) and + result = MkElementFilter() } // Summaries and their stacks From 3c80652b9175583beb50d7106d98ee174e5d8c91 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 4 Oct 2024 19:19:19 +0100 Subject: [PATCH 6/9] PS: Autoformat and silence 'unused paramter' warning. --- .../code/powershell/dataflow/internal/DataFlowPrivate.qll | 3 ++- .../code/powershell/dataflow/internal/DataFlowPublic.qll | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) 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 815df034a5a..05b1cb7d50b 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll @@ -587,7 +587,8 @@ predicate localMustFlowStep(Node node1, Node node2) { none() } /** Gets the type of `n` used for type pruning. */ DataFlowType getNodeType(Node n) { - result = TUnknownDataFlowType() // TODO + result = TUnknownDataFlowType() and // TODO + exists(n) } pragma[inline] 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 03ceb54bfd2..76b21030a89 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll @@ -298,7 +298,7 @@ module BarrierGuard { /** * A dataflow node that represents the creation of an object. - * + * * For example, `[Foo]::new()` or `New-Object Foo`. */ class ObjectCreationNode extends Node { From 1de38e2cbc5825ae0db46f1b9faad2dcb15e046a Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 4 Oct 2024 19:48:44 +0100 Subject: [PATCH 7/9] PS: Accept test changes. --- .../dataflow/fields/test.expected | 287 ++++++++++++++++++ .../library-tests/dataflow/fields/test.ps1 | 16 +- 2 files changed, 295 insertions(+), 8 deletions(-) diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.expected b/powershell/ql/test/library-tests/dataflow/fields/test.expected index a8284136deb..c28d812c778 100644 --- a/powershell/ql/test/library-tests/dataflow/fields/test.expected +++ b/powershell/ql/test/library-tests/dataflow/fields/test.expected @@ -3,12 +3,299 @@ edges | test.ps1:1:1:1:3 | [post] a [f] | test.ps1:2:6:2:8 | a [f] | provenance | | | test.ps1:1:8:1:18 | Source | test.ps1:1:1:1:3 | [post] a [f] | provenance | | | test.ps1:2:6:2:8 | a [f] | test.ps1:2:6:2:10 | f | provenance | | +| test.ps1:8:1:8:6 | [post] arr1 [element 3] | test.ps1:9:6:9:11 | arr1 [element 3] | provenance | | +| test.ps1:8:12:8:22 | Source | test.ps1:8:1:8:6 | [post] arr1 [element 3] | provenance | | +| test.ps1:9:6:9:11 | arr1 [element 3] | test.ps1:9:6:9:14 | ...[...] | provenance | | +| test.ps1:12:1:12:6 | [post] arr2 [element 4] | test.ps1:13:6:13:11 | arr2 [element 4] | provenance | | +| test.ps1:12:19:12:29 | Source | test.ps1:12:1:12:6 | [post] arr2 [element 4] | provenance | | +| test.ps1:13:6:13:11 | arr2 [element 4] | test.ps1:13:6:13:14 | ...[...] | provenance | | +| test.ps1:15:1:15:6 | [post] arr3 [element 3] | test.ps1:16:6:16:11 | arr3 [element 3] | provenance | | +| test.ps1:15:12:15:22 | Source | test.ps1:15:1:15:6 | [post] arr3 [element 3] | provenance | | +| test.ps1:16:6:16:11 | arr3 [element 3] | test.ps1:16:6:16:21 | ...[...] | provenance | | +| test.ps1:18:1:18:6 | [post] arr4 [element 0] | test.ps1:19:6:19:11 | arr4 [element 0] | provenance | | +| test.ps1:18:1:18:6 | [post] arr4 [element 1] | test.ps1:19:6:19:11 | arr4 [element 1] | provenance | | +| test.ps1:18:1:18:6 | [post] arr4 [element 2] | test.ps1:19:6:19:11 | arr4 [element 2] | provenance | | +| test.ps1:18:1:18:6 | [post] arr4 [element 3] | test.ps1:19:6:19:11 | arr4 [element 3] | provenance | | +| test.ps1:18:1:18:6 | [post] arr4 [element 4] | test.ps1:19:6:19:11 | arr4 [element 4] | provenance | | +| test.ps1:18:20:18:30 | Source | test.ps1:18:1:18:6 | [post] arr4 [element 0] | provenance | | +| test.ps1:18:20:18:30 | Source | test.ps1:18:1:18:6 | [post] arr4 [element 1] | provenance | | +| test.ps1:18:20:18:30 | Source | test.ps1:18:1:18:6 | [post] arr4 [element 2] | provenance | | +| test.ps1:18:20:18:30 | Source | test.ps1:18:1:18:6 | [post] arr4 [element 3] | provenance | | +| test.ps1:18:20:18:30 | Source | test.ps1:18:1:18:6 | [post] arr4 [element 4] | provenance | | +| test.ps1:19:6:19:11 | arr4 [element 0] | test.ps1:19:6:19:22 | ...[...] | provenance | | +| test.ps1:19:6:19:11 | arr4 [element 1] | test.ps1:19:6:19:22 | ...[...] | provenance | | +| test.ps1:19:6:19:11 | arr4 [element 2] | test.ps1:19:6:19:22 | ...[...] | provenance | | +| test.ps1:19:6:19:11 | arr4 [element 3] | test.ps1:19:6:19:22 | ...[...] | provenance | | +| test.ps1:19:6:19:11 | arr4 [element 4] | test.ps1:19:6:19:22 | ...[...] | provenance | | +| test.ps1:21:1:21:6 | [post] arr5 [element 0, element 1] | test.ps1:22:6:22:11 | arr5 [element 0, element 1] | provenance | | +| test.ps1:21:1:21:6 | [post] arr5 [element 1, element 1] | test.ps1:22:6:22:11 | arr5 [element 1, element 1] | provenance | | +| test.ps1:21:1:21:6 | [post] arr5 [element 2, element 1] | test.ps1:22:6:22:11 | arr5 [element 2, element 1] | provenance | | +| test.ps1:21:1:21:6 | [post] arr5 [element 3, element 1] | test.ps1:22:6:22:11 | arr5 [element 3, element 1] | provenance | | +| test.ps1:21:1:21:6 | [post] arr5 [element 4, element 1] | test.ps1:22:6:22:11 | arr5 [element 4, element 1] | provenance | | +| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | test.ps1:21:1:21:6 | [post] arr5 [element 0, element 1] | provenance | | +| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | test.ps1:21:1:21:6 | [post] arr5 [element 1, element 1] | provenance | | +| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | test.ps1:21:1:21:6 | [post] arr5 [element 2, element 1] | provenance | | +| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | test.ps1:21:1:21:6 | [post] arr5 [element 3, element 1] | provenance | | +| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | test.ps1:21:1:21:6 | [post] arr5 [element 4, element 1] | provenance | | +| test.ps1:21:23:21:33 | Source | test.ps1:21:1:21:17 | [post] ...[...] [element 1] | provenance | | +| test.ps1:22:6:22:11 | arr5 [element 0, element 1] | test.ps1:22:6:22:22 | ...[...] [element 1] | provenance | | +| test.ps1:22:6:22:11 | arr5 [element 1, element 1] | test.ps1:22:6:22:22 | ...[...] [element 1] | provenance | | +| test.ps1:22:6:22:11 | arr5 [element 2, element 1] | test.ps1:22:6:22:22 | ...[...] [element 1] | provenance | | +| test.ps1:22:6:22:11 | arr5 [element 3, element 1] | test.ps1:22:6:22:22 | ...[...] [element 1] | provenance | | +| test.ps1:22:6:22:11 | arr5 [element 4, element 1] | test.ps1:22:6:22:22 | ...[...] [element 1] | provenance | | +| test.ps1:22:6:22:22 | ...[...] [element 1] | test.ps1:22:6:22:25 | ...[...] | provenance | | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 0] | test.ps1:26:6:26:11 | arr6 [element 1, element 0] | provenance | | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 1] | test.ps1:26:6:26:11 | arr6 [element 1, element 1] | provenance | | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 2] | test.ps1:26:6:26:11 | arr6 [element 1, element 2] | provenance | | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 3] | test.ps1:26:6:26:11 | arr6 [element 1, element 3] | provenance | | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 4] | test.ps1:26:6:26:11 | arr6 [element 1, element 4] | provenance | | +| test.ps1:25:1:25:9 | [post] ...[...] [element 0] | test.ps1:25:1:25:6 | [post] arr6 [element 1, element 0] | provenance | | +| test.ps1:25:1:25:9 | [post] ...[...] [element 1] | test.ps1:25:1:25:6 | [post] arr6 [element 1, element 1] | provenance | | +| test.ps1:25:1:25:9 | [post] ...[...] [element 2] | test.ps1:25:1:25:6 | [post] arr6 [element 1, element 2] | provenance | | +| test.ps1:25:1:25:9 | [post] ...[...] [element 3] | test.ps1:25:1:25:6 | [post] arr6 [element 1, element 3] | provenance | | +| test.ps1:25:1:25:9 | [post] ...[...] [element 4] | test.ps1:25:1:25:6 | [post] arr6 [element 1, element 4] | provenance | | +| test.ps1:25:23:25:33 | Source | test.ps1:25:1:25:9 | [post] ...[...] [element 0] | provenance | | +| test.ps1:25:23:25:33 | Source | test.ps1:25:1:25:9 | [post] ...[...] [element 1] | provenance | | +| test.ps1:25:23:25:33 | Source | test.ps1:25:1:25:9 | [post] ...[...] [element 2] | provenance | | +| test.ps1:25:23:25:33 | Source | test.ps1:25:1:25:9 | [post] ...[...] [element 3] | provenance | | +| test.ps1:25:23:25:33 | Source | test.ps1:25:1:25:9 | [post] ...[...] [element 4] | provenance | | +| test.ps1:26:6:26:11 | arr6 [element 1, element 0] | test.ps1:26:6:26:14 | ...[...] [element 0] | provenance | | +| test.ps1:26:6:26:11 | arr6 [element 1, element 1] | test.ps1:26:6:26:14 | ...[...] [element 1] | provenance | | +| test.ps1:26:6:26:11 | arr6 [element 1, element 2] | test.ps1:26:6:26:14 | ...[...] [element 2] | provenance | | +| test.ps1:26:6:26:11 | arr6 [element 1, element 3] | test.ps1:26:6:26:14 | ...[...] [element 3] | provenance | | +| test.ps1:26:6:26:11 | arr6 [element 1, element 4] | test.ps1:26:6:26:14 | ...[...] [element 4] | provenance | | +| test.ps1:26:6:26:14 | ...[...] [element 0] | test.ps1:26:6:26:25 | ...[...] | provenance | | +| test.ps1:26:6:26:14 | ...[...] [element 1] | test.ps1:26:6:26:25 | ...[...] | provenance | | +| test.ps1:26:6:26:14 | ...[...] [element 2] | test.ps1:26:6:26:25 | ...[...] | provenance | | +| test.ps1:26:6:26:14 | ...[...] [element 3] | test.ps1:26:6:26:25 | ...[...] | provenance | | +| test.ps1:26:6:26:14 | ...[...] [element 4] | test.ps1:26:6:26:25 | ...[...] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 0] | test.ps1:31:6:31:11 | arr7 [element 0, element 0] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 1] | test.ps1:31:6:31:11 | arr7 [element 0, element 1] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 2] | test.ps1:31:6:31:11 | arr7 [element 0, element 2] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 3] | test.ps1:31:6:31:11 | arr7 [element 0, element 3] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 4] | test.ps1:31:6:31:11 | arr7 [element 0, element 4] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 0] | test.ps1:31:6:31:11 | arr7 [element 1, element 0] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 1] | test.ps1:31:6:31:11 | arr7 [element 1, element 1] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 2] | test.ps1:30:6:30:11 | arr7 [element 1, element 2] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 2] | test.ps1:31:6:31:11 | arr7 [element 1, element 2] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 3] | test.ps1:31:6:31:11 | arr7 [element 1, element 3] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 4] | test.ps1:31:6:31:11 | arr7 [element 1, element 4] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 0] | test.ps1:31:6:31:11 | arr7 [element 2, element 0] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 1] | test.ps1:31:6:31:11 | arr7 [element 2, element 1] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 2] | test.ps1:31:6:31:11 | arr7 [element 2, element 2] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 3] | test.ps1:31:6:31:11 | arr7 [element 2, element 3] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 4] | test.ps1:31:6:31:11 | arr7 [element 2, element 4] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 0] | test.ps1:31:6:31:11 | arr7 [element 3, element 0] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 1] | test.ps1:31:6:31:11 | arr7 [element 3, element 1] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 2] | test.ps1:31:6:31:11 | arr7 [element 3, element 2] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 3] | test.ps1:31:6:31:11 | arr7 [element 3, element 3] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 4] | test.ps1:31:6:31:11 | arr7 [element 3, element 4] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 0] | test.ps1:31:6:31:11 | arr7 [element 4, element 0] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 1] | test.ps1:31:6:31:11 | arr7 [element 4, element 1] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 2] | test.ps1:31:6:31:11 | arr7 [element 4, element 2] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 3] | test.ps1:31:6:31:11 | arr7 [element 4, element 3] | provenance | | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 4] | test.ps1:31:6:31:11 | arr7 [element 4, element 4] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 0] | test.ps1:29:1:29:6 | [post] arr7 [element 0, element 0] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 0] | test.ps1:29:1:29:6 | [post] arr7 [element 1, element 0] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 0] | test.ps1:29:1:29:6 | [post] arr7 [element 2, element 0] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 0] | test.ps1:29:1:29:6 | [post] arr7 [element 3, element 0] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 0] | test.ps1:29:1:29:6 | [post] arr7 [element 4, element 0] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 1] | test.ps1:29:1:29:6 | [post] arr7 [element 0, element 1] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 1] | test.ps1:29:1:29:6 | [post] arr7 [element 1, element 1] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 1] | test.ps1:29:1:29:6 | [post] arr7 [element 2, element 1] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 1] | test.ps1:29:1:29:6 | [post] arr7 [element 3, element 1] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 1] | test.ps1:29:1:29:6 | [post] arr7 [element 4, element 1] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 2] | test.ps1:29:1:29:6 | [post] arr7 [element 0, element 2] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 2] | test.ps1:29:1:29:6 | [post] arr7 [element 1, element 2] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 2] | test.ps1:29:1:29:6 | [post] arr7 [element 2, element 2] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 2] | test.ps1:29:1:29:6 | [post] arr7 [element 3, element 2] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 2] | test.ps1:29:1:29:6 | [post] arr7 [element 4, element 2] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 3] | test.ps1:29:1:29:6 | [post] arr7 [element 0, element 3] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 3] | test.ps1:29:1:29:6 | [post] arr7 [element 1, element 3] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 3] | test.ps1:29:1:29:6 | [post] arr7 [element 2, element 3] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 3] | test.ps1:29:1:29:6 | [post] arr7 [element 3, element 3] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 3] | test.ps1:29:1:29:6 | [post] arr7 [element 4, element 3] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 4] | test.ps1:29:1:29:6 | [post] arr7 [element 0, element 4] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 4] | test.ps1:29:1:29:6 | [post] arr7 [element 1, element 4] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 4] | test.ps1:29:1:29:6 | [post] arr7 [element 2, element 4] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 4] | test.ps1:29:1:29:6 | [post] arr7 [element 3, element 4] | provenance | | +| test.ps1:29:1:29:17 | [post] ...[...] [element 4] | test.ps1:29:1:29:6 | [post] arr7 [element 4, element 4] | provenance | | +| test.ps1:29:31:29:41 | Source | test.ps1:29:1:29:17 | [post] ...[...] [element 0] | provenance | | +| test.ps1:29:31:29:41 | Source | test.ps1:29:1:29:17 | [post] ...[...] [element 1] | provenance | | +| test.ps1:29:31:29:41 | Source | test.ps1:29:1:29:17 | [post] ...[...] [element 2] | provenance | | +| test.ps1:29:31:29:41 | Source | test.ps1:29:1:29:17 | [post] ...[...] [element 3] | provenance | | +| test.ps1:29:31:29:41 | Source | test.ps1:29:1:29:17 | [post] ...[...] [element 4] | provenance | | +| test.ps1:30:6:30:11 | arr7 [element 1, element 2] | test.ps1:30:6:30:14 | ...[...] [element 2] | provenance | | +| test.ps1:30:6:30:14 | ...[...] [element 2] | test.ps1:30:6:30:17 | ...[...] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 0, element 0] | test.ps1:31:6:31:22 | ...[...] [element 0] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 0, element 1] | test.ps1:31:6:31:22 | ...[...] [element 1] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 0, element 2] | test.ps1:31:6:31:22 | ...[...] [element 2] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 0, element 3] | test.ps1:31:6:31:22 | ...[...] [element 3] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 0, element 4] | test.ps1:31:6:31:22 | ...[...] [element 4] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 1, element 0] | test.ps1:31:6:31:22 | ...[...] [element 0] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 1, element 1] | test.ps1:31:6:31:22 | ...[...] [element 1] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 1, element 2] | test.ps1:31:6:31:22 | ...[...] [element 2] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 1, element 3] | test.ps1:31:6:31:22 | ...[...] [element 3] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 1, element 4] | test.ps1:31:6:31:22 | ...[...] [element 4] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 2, element 0] | test.ps1:31:6:31:22 | ...[...] [element 0] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 2, element 1] | test.ps1:31:6:31:22 | ...[...] [element 1] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 2, element 2] | test.ps1:31:6:31:22 | ...[...] [element 2] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 2, element 3] | test.ps1:31:6:31:22 | ...[...] [element 3] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 2, element 4] | test.ps1:31:6:31:22 | ...[...] [element 4] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 3, element 0] | test.ps1:31:6:31:22 | ...[...] [element 0] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 3, element 1] | test.ps1:31:6:31:22 | ...[...] [element 1] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 3, element 2] | test.ps1:31:6:31:22 | ...[...] [element 2] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 3, element 3] | test.ps1:31:6:31:22 | ...[...] [element 3] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 3, element 4] | test.ps1:31:6:31:22 | ...[...] [element 4] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 4, element 0] | test.ps1:31:6:31:22 | ...[...] [element 0] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 4, element 1] | test.ps1:31:6:31:22 | ...[...] [element 1] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 4, element 2] | test.ps1:31:6:31:22 | ...[...] [element 2] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 4, element 3] | test.ps1:31:6:31:22 | ...[...] [element 3] | provenance | | +| test.ps1:31:6:31:11 | arr7 [element 4, element 4] | test.ps1:31:6:31:22 | ...[...] [element 4] | provenance | | +| test.ps1:31:6:31:22 | ...[...] [element 0] | test.ps1:31:6:31:33 | ...[...] | provenance | | +| test.ps1:31:6:31:22 | ...[...] [element 1] | test.ps1:31:6:31:33 | ...[...] | provenance | | +| test.ps1:31:6:31:22 | ...[...] [element 2] | test.ps1:31:6:31:33 | ...[...] | provenance | | +| test.ps1:31:6:31:22 | ...[...] [element 3] | test.ps1:31:6:31:33 | ...[...] | provenance | | +| test.ps1:31:6:31:22 | ...[...] [element 4] | test.ps1:31:6:31:33 | ...[...] | provenance | | nodes | test.ps1:1:1:1:3 | [post] a [f] | semmle.label | [post] a [f] | | test.ps1:1:8:1:18 | Source | semmle.label | Source | | test.ps1:2:6:2:8 | a [f] | semmle.label | a [f] | | test.ps1:2:6:2:10 | f | semmle.label | f | +| test.ps1:8:1:8:6 | [post] arr1 [element 3] | semmle.label | [post] arr1 [element 3] | +| test.ps1:8:12:8:22 | Source | semmle.label | Source | +| test.ps1:9:6:9:11 | arr1 [element 3] | semmle.label | arr1 [element 3] | +| test.ps1:9:6:9:14 | ...[...] | semmle.label | ...[...] | +| test.ps1:12:1:12:6 | [post] arr2 [element 4] | semmle.label | [post] arr2 [element 4] | +| test.ps1:12:19:12:29 | Source | semmle.label | Source | +| test.ps1:13:6:13:11 | arr2 [element 4] | semmle.label | arr2 [element 4] | +| test.ps1:13:6:13:14 | ...[...] | semmle.label | ...[...] | +| test.ps1:15:1:15:6 | [post] arr3 [element 3] | semmle.label | [post] arr3 [element 3] | +| test.ps1:15:12:15:22 | Source | semmle.label | Source | +| test.ps1:16:6:16:11 | arr3 [element 3] | semmle.label | arr3 [element 3] | +| test.ps1:16:6:16:21 | ...[...] | semmle.label | ...[...] | +| test.ps1:18:1:18:6 | [post] arr4 [element 0] | semmle.label | [post] arr4 [element 0] | +| test.ps1:18:1:18:6 | [post] arr4 [element 1] | semmle.label | [post] arr4 [element 1] | +| test.ps1:18:1:18:6 | [post] arr4 [element 2] | semmle.label | [post] arr4 [element 2] | +| test.ps1:18:1:18:6 | [post] arr4 [element 3] | semmle.label | [post] arr4 [element 3] | +| test.ps1:18:1:18:6 | [post] arr4 [element 4] | semmle.label | [post] arr4 [element 4] | +| test.ps1:18:20:18:30 | Source | semmle.label | Source | +| test.ps1:19:6:19:11 | arr4 [element 0] | semmle.label | arr4 [element 0] | +| test.ps1:19:6:19:11 | arr4 [element 1] | semmle.label | arr4 [element 1] | +| test.ps1:19:6:19:11 | arr4 [element 2] | semmle.label | arr4 [element 2] | +| test.ps1:19:6:19:11 | arr4 [element 3] | semmle.label | arr4 [element 3] | +| test.ps1:19:6:19:11 | arr4 [element 4] | semmle.label | arr4 [element 4] | +| test.ps1:19:6:19:22 | ...[...] | semmle.label | ...[...] | +| test.ps1:21:1:21:6 | [post] arr5 [element 0, element 1] | semmle.label | [post] arr5 [element 0, element 1] | +| test.ps1:21:1:21:6 | [post] arr5 [element 1, element 1] | semmle.label | [post] arr5 [element 1, element 1] | +| test.ps1:21:1:21:6 | [post] arr5 [element 2, element 1] | semmle.label | [post] arr5 [element 2, element 1] | +| test.ps1:21:1:21:6 | [post] arr5 [element 3, element 1] | semmle.label | [post] arr5 [element 3, element 1] | +| test.ps1:21:1:21:6 | [post] arr5 [element 4, element 1] | semmle.label | [post] arr5 [element 4, element 1] | +| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | semmle.label | [post] ...[...] [element 1] | +| test.ps1:21:23:21:33 | Source | semmle.label | Source | +| test.ps1:22:6:22:11 | arr5 [element 0, element 1] | semmle.label | arr5 [element 0, element 1] | +| test.ps1:22:6:22:11 | arr5 [element 1, element 1] | semmle.label | arr5 [element 1, element 1] | +| test.ps1:22:6:22:11 | arr5 [element 2, element 1] | semmle.label | arr5 [element 2, element 1] | +| test.ps1:22:6:22:11 | arr5 [element 3, element 1] | semmle.label | arr5 [element 3, element 1] | +| test.ps1:22:6:22:11 | arr5 [element 4, element 1] | semmle.label | arr5 [element 4, element 1] | +| test.ps1:22:6:22:22 | ...[...] [element 1] | semmle.label | ...[...] [element 1] | +| test.ps1:22:6:22:25 | ...[...] | semmle.label | ...[...] | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 0] | semmle.label | [post] arr6 [element 1, element 0] | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 1] | semmle.label | [post] arr6 [element 1, element 1] | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 2] | semmle.label | [post] arr6 [element 1, element 2] | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 3] | semmle.label | [post] arr6 [element 1, element 3] | +| test.ps1:25:1:25:6 | [post] arr6 [element 1, element 4] | semmle.label | [post] arr6 [element 1, element 4] | +| test.ps1:25:1:25:9 | [post] ...[...] [element 0] | semmle.label | [post] ...[...] [element 0] | +| test.ps1:25:1:25:9 | [post] ...[...] [element 1] | semmle.label | [post] ...[...] [element 1] | +| test.ps1:25:1:25:9 | [post] ...[...] [element 2] | semmle.label | [post] ...[...] [element 2] | +| test.ps1:25:1:25:9 | [post] ...[...] [element 3] | semmle.label | [post] ...[...] [element 3] | +| test.ps1:25:1:25:9 | [post] ...[...] [element 4] | semmle.label | [post] ...[...] [element 4] | +| test.ps1:25:23:25:33 | Source | semmle.label | Source | +| test.ps1:26:6:26:11 | arr6 [element 1, element 0] | semmle.label | arr6 [element 1, element 0] | +| test.ps1:26:6:26:11 | arr6 [element 1, element 1] | semmle.label | arr6 [element 1, element 1] | +| test.ps1:26:6:26:11 | arr6 [element 1, element 2] | semmle.label | arr6 [element 1, element 2] | +| test.ps1:26:6:26:11 | arr6 [element 1, element 3] | semmle.label | arr6 [element 1, element 3] | +| test.ps1:26:6:26:11 | arr6 [element 1, element 4] | semmle.label | arr6 [element 1, element 4] | +| test.ps1:26:6:26:14 | ...[...] [element 0] | semmle.label | ...[...] [element 0] | +| test.ps1:26:6:26:14 | ...[...] [element 1] | semmle.label | ...[...] [element 1] | +| test.ps1:26:6:26:14 | ...[...] [element 2] | semmle.label | ...[...] [element 2] | +| test.ps1:26:6:26:14 | ...[...] [element 3] | semmle.label | ...[...] [element 3] | +| test.ps1:26:6:26:14 | ...[...] [element 4] | semmle.label | ...[...] [element 4] | +| test.ps1:26:6:26:25 | ...[...] | semmle.label | ...[...] | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 0] | semmle.label | [post] arr7 [element 0, element 0] | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 1] | semmle.label | [post] arr7 [element 0, element 1] | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 2] | semmle.label | [post] arr7 [element 0, element 2] | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 3] | semmle.label | [post] arr7 [element 0, element 3] | +| test.ps1:29:1:29:6 | [post] arr7 [element 0, element 4] | semmle.label | [post] arr7 [element 0, element 4] | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 0] | semmle.label | [post] arr7 [element 1, element 0] | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 1] | semmle.label | [post] arr7 [element 1, element 1] | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 2] | semmle.label | [post] arr7 [element 1, element 2] | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 3] | semmle.label | [post] arr7 [element 1, element 3] | +| test.ps1:29:1:29:6 | [post] arr7 [element 1, element 4] | semmle.label | [post] arr7 [element 1, element 4] | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 0] | semmle.label | [post] arr7 [element 2, element 0] | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 1] | semmle.label | [post] arr7 [element 2, element 1] | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 2] | semmle.label | [post] arr7 [element 2, element 2] | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 3] | semmle.label | [post] arr7 [element 2, element 3] | +| test.ps1:29:1:29:6 | [post] arr7 [element 2, element 4] | semmle.label | [post] arr7 [element 2, element 4] | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 0] | semmle.label | [post] arr7 [element 3, element 0] | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 1] | semmle.label | [post] arr7 [element 3, element 1] | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 2] | semmle.label | [post] arr7 [element 3, element 2] | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 3] | semmle.label | [post] arr7 [element 3, element 3] | +| test.ps1:29:1:29:6 | [post] arr7 [element 3, element 4] | semmle.label | [post] arr7 [element 3, element 4] | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 0] | semmle.label | [post] arr7 [element 4, element 0] | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 1] | semmle.label | [post] arr7 [element 4, element 1] | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 2] | semmle.label | [post] arr7 [element 4, element 2] | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 3] | semmle.label | [post] arr7 [element 4, element 3] | +| test.ps1:29:1:29:6 | [post] arr7 [element 4, element 4] | semmle.label | [post] arr7 [element 4, element 4] | +| test.ps1:29:1:29:17 | [post] ...[...] [element 0] | semmle.label | [post] ...[...] [element 0] | +| test.ps1:29:1:29:17 | [post] ...[...] [element 1] | semmle.label | [post] ...[...] [element 1] | +| test.ps1:29:1:29:17 | [post] ...[...] [element 2] | semmle.label | [post] ...[...] [element 2] | +| test.ps1:29:1:29:17 | [post] ...[...] [element 3] | semmle.label | [post] ...[...] [element 3] | +| test.ps1:29:1:29:17 | [post] ...[...] [element 4] | semmle.label | [post] ...[...] [element 4] | +| test.ps1:29:31:29:41 | Source | semmle.label | Source | +| test.ps1:30:6:30:11 | arr7 [element 1, element 2] | semmle.label | arr7 [element 1, element 2] | +| test.ps1:30:6:30:14 | ...[...] [element 2] | semmle.label | ...[...] [element 2] | +| test.ps1:30:6:30:17 | ...[...] | semmle.label | ...[...] | +| test.ps1:31:6:31:11 | arr7 [element 0, element 0] | semmle.label | arr7 [element 0, element 0] | +| test.ps1:31:6:31:11 | arr7 [element 0, element 1] | semmle.label | arr7 [element 0, element 1] | +| test.ps1:31:6:31:11 | arr7 [element 0, element 2] | semmle.label | arr7 [element 0, element 2] | +| test.ps1:31:6:31:11 | arr7 [element 0, element 3] | semmle.label | arr7 [element 0, element 3] | +| test.ps1:31:6:31:11 | arr7 [element 0, element 4] | semmle.label | arr7 [element 0, element 4] | +| test.ps1:31:6:31:11 | arr7 [element 1, element 0] | semmle.label | arr7 [element 1, element 0] | +| test.ps1:31:6:31:11 | arr7 [element 1, element 1] | semmle.label | arr7 [element 1, element 1] | +| test.ps1:31:6:31:11 | arr7 [element 1, element 2] | semmle.label | arr7 [element 1, element 2] | +| test.ps1:31:6:31:11 | arr7 [element 1, element 3] | semmle.label | arr7 [element 1, element 3] | +| test.ps1:31:6:31:11 | arr7 [element 1, element 4] | semmle.label | arr7 [element 1, element 4] | +| test.ps1:31:6:31:11 | arr7 [element 2, element 0] | semmle.label | arr7 [element 2, element 0] | +| test.ps1:31:6:31:11 | arr7 [element 2, element 1] | semmle.label | arr7 [element 2, element 1] | +| test.ps1:31:6:31:11 | arr7 [element 2, element 2] | semmle.label | arr7 [element 2, element 2] | +| test.ps1:31:6:31:11 | arr7 [element 2, element 3] | semmle.label | arr7 [element 2, element 3] | +| test.ps1:31:6:31:11 | arr7 [element 2, element 4] | semmle.label | arr7 [element 2, element 4] | +| test.ps1:31:6:31:11 | arr7 [element 3, element 0] | semmle.label | arr7 [element 3, element 0] | +| test.ps1:31:6:31:11 | arr7 [element 3, element 1] | semmle.label | arr7 [element 3, element 1] | +| test.ps1:31:6:31:11 | arr7 [element 3, element 2] | semmle.label | arr7 [element 3, element 2] | +| test.ps1:31:6:31:11 | arr7 [element 3, element 3] | semmle.label | arr7 [element 3, element 3] | +| test.ps1:31:6:31:11 | arr7 [element 3, element 4] | semmle.label | arr7 [element 3, element 4] | +| test.ps1:31:6:31:11 | arr7 [element 4, element 0] | semmle.label | arr7 [element 4, element 0] | +| test.ps1:31:6:31:11 | arr7 [element 4, element 1] | semmle.label | arr7 [element 4, element 1] | +| test.ps1:31:6:31:11 | arr7 [element 4, element 2] | semmle.label | arr7 [element 4, element 2] | +| test.ps1:31:6:31:11 | arr7 [element 4, element 3] | semmle.label | arr7 [element 4, element 3] | +| test.ps1:31:6:31:11 | arr7 [element 4, element 4] | semmle.label | arr7 [element 4, element 4] | +| test.ps1:31:6:31:22 | ...[...] [element 0] | semmle.label | ...[...] [element 0] | +| test.ps1:31:6:31:22 | ...[...] [element 1] | semmle.label | ...[...] [element 1] | +| test.ps1:31:6:31:22 | ...[...] [element 2] | semmle.label | ...[...] [element 2] | +| test.ps1:31:6:31:22 | ...[...] [element 3] | semmle.label | ...[...] [element 3] | +| test.ps1:31:6:31:22 | ...[...] [element 4] | semmle.label | ...[...] [element 4] | +| test.ps1:31:6:31:33 | ...[...] | semmle.label | ...[...] | subpaths testFailures #select | test.ps1:2:6:2:10 | f | test.ps1:1:8:1:18 | Source | test.ps1:2:6:2:10 | f | $@ | test.ps1:1:8:1:18 | Source | Source | +| test.ps1:9:6:9:14 | ...[...] | test.ps1:8:12:8:22 | Source | test.ps1:9:6:9:14 | ...[...] | $@ | test.ps1:8:12:8:22 | Source | Source | +| test.ps1:13:6:13:14 | ...[...] | test.ps1:12:19:12:29 | Source | test.ps1:13:6:13:14 | ...[...] | $@ | test.ps1:12:19:12:29 | Source | Source | +| test.ps1:16:6:16:21 | ...[...] | test.ps1:15:12:15:22 | Source | test.ps1:16:6:16:21 | ...[...] | $@ | test.ps1:15:12:15:22 | Source | Source | +| test.ps1:19:6:19:22 | ...[...] | test.ps1:18:20:18:30 | Source | test.ps1:19:6:19:22 | ...[...] | $@ | test.ps1:18:20:18:30 | Source | Source | +| test.ps1:22:6:22:25 | ...[...] | test.ps1:21:23:21:33 | Source | test.ps1:22:6:22:25 | ...[...] | $@ | test.ps1:21:23:21:33 | Source | Source | +| test.ps1:26:6:26:25 | ...[...] | test.ps1:25:23:25:33 | Source | test.ps1:26:6:26:25 | ...[...] | $@ | test.ps1:25:23:25:33 | Source | Source | +| test.ps1:30:6:30:17 | ...[...] | test.ps1:29:31:29:41 | Source | test.ps1:30:6:30:17 | ...[...] | $@ | test.ps1:29:31:29:41 | Source | Source | +| test.ps1:31:6:31:33 | ...[...] | test.ps1:29:31:29:41 | Source | test.ps1:31:6:31:33 | ...[...] | $@ | test.ps1:29:31:29:41 | Source | Source | diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 index 4e0dc1d33a8..2428cb80be4 100644 --- a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 +++ b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 @@ -6,26 +6,26 @@ $a.f = 0 Sink $a.f # clean $arr1[3] = Source "3" -Sink $arr1[3] # $ MISSING: hasValueFlow=3 +Sink $arr1[3] # $ hasValueFlow=3 Sink $arr1[4] # clean $arr2[$unknown] = Source "4" -Sink $arr2[4] # $ MISSING: hasValueFlow=4 +Sink $arr2[4] # $ hasValueFlow=4 $arr3[3] = Source "5" -Sink $arr3[$unknown] # $ MISSING: hasValueFlow=5 +Sink $arr3[$unknown] # $ hasValueFlow=5 $arr4[$unknown1] = Source "6" -Sink $arr4[$unknown2] # $ MISSING: hasValueFlow=6 +Sink $arr4[$unknown2] # $ hasValueFlow=6 $arr5[$unknown3][1] = Source "7" -Sink $arr5[$unknown3][1] # $ MISSING: hasValueFlow=7 +Sink $arr5[$unknown3][1] # $ hasValueFlow=7 Sink $arr5[$unknown3][2] # clean $arr6[1][$unknown4] = Source "8" -Sink $arr6[1][$unknown4] # $ MISSING: hasValueFlow=8 +Sink $arr6[1][$unknown4] # $ hasValueFlow=8 Sink $arr6[2][$unknown4] # clean $arr7[$unknown5][$unknown6] = Source "9" -Sink $arr7[1][2] # $ MISSING: hasValueFlow=9 -Sink $arr7[$unknown7][$unknown8] # $ MISSING: hasValueFlow=9 \ No newline at end of file +Sink $arr7[1][2] # $ hasValueFlow=9 +Sink $arr7[$unknown7][$unknown8] # $ hasValueFlow=9 \ No newline at end of file From 4d8809a808d878ffaa089579a36e4dc4c9349bb3 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 4 Oct 2024 19:52:56 +0100 Subject: [PATCH 8/9] PS: Add another class of missing flow. --- .../library-tests/dataflow/fields/test.ps1 | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 index 2428cb80be4..6b480820c5b 100644 --- a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 +++ b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 @@ -28,4 +28,20 @@ Sink $arr6[2][$unknown4] # clean $arr7[$unknown5][$unknown6] = Source "9" Sink $arr7[1][2] # $ hasValueFlow=9 -Sink $arr7[$unknown7][$unknown8] # $ hasValueFlow=9 \ No newline at end of file +Sink $arr7[$unknown7][$unknown8] # $ hasValueFlow=9 + +$x = Source "10" + +$arr8 = 0, 1, $x +Sink $arr8[0] # clean +Sink $arr8[1] # clean +Sink $arr8[2] # $ MISSING: hasValueFlow=10 +Sink $arr8[$unknown] # MISSING: hasValueFlow=10 + +$y = Source "11" + +$arr9 = @(0, 1, $y) +Sink $arr9[0] # clean +Sink $arr9[1] # clean +Sink $arr9[2] # $ MISSING: hasValueFlow=11 +Sink $arr9[$unknown] # MISSING: hasValueFlow=11 \ No newline at end of file From 494ef7a44cbd8e8871f9252b5aca99e7a2fd9955 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 4 Oct 2024 20:08:20 +0100 Subject: [PATCH 9/9] PS: Fix missing flow. --- .../dataflow/internal/DataFlowPrivate.qll | 6 ++++++ .../library-tests/dataflow/fields/test.expected | 15 +++++++++++++++ .../test/library-tests/dataflow/fields/test.ps1 | 4 ++-- 3 files changed, 23 insertions(+), 2 deletions(-) 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 05b1cb7d50b..a39c42b2139 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll @@ -528,6 +528,12 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { or not exists(e.getValue().asInt()) ) + or + exists(Content::KnownElementContent ec, int index | + node2.asExpr().(CfgNodes::ExprNodes::ArrayLiteralCfgNode).getElement(index) = node1.asExpr() and + c.isKnownOrUnknownElement(ec) and + index = ec.getIndex().asInt() + ) } /** diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.expected b/powershell/ql/test/library-tests/dataflow/fields/test.expected index c28d812c778..50635fd5358 100644 --- a/powershell/ql/test/library-tests/dataflow/fields/test.expected +++ b/powershell/ql/test/library-tests/dataflow/fields/test.expected @@ -157,6 +157,12 @@ edges | test.ps1:31:6:31:22 | ...[...] [element 2] | test.ps1:31:6:31:33 | ...[...] | provenance | | | test.ps1:31:6:31:22 | ...[...] [element 3] | test.ps1:31:6:31:33 | ...[...] | provenance | | | test.ps1:31:6:31:22 | ...[...] [element 4] | test.ps1:31:6:31:33 | ...[...] | provenance | | +| test.ps1:33:6:33:17 | Source | test.ps1:35:15:35:17 | x | provenance | | +| test.ps1:35:9:35:17 | ...,... [element 2] | test.ps1:38:6:38:11 | arr8 [element 2] | provenance | | +| test.ps1:35:9:35:17 | ...,... [element 2] | test.ps1:39:6:39:11 | arr8 [element 2] | provenance | | +| test.ps1:35:15:35:17 | x | test.ps1:35:9:35:17 | ...,... [element 2] | provenance | | +| test.ps1:38:6:38:11 | arr8 [element 2] | test.ps1:38:6:38:14 | ...[...] | provenance | | +| test.ps1:39:6:39:11 | arr8 [element 2] | test.ps1:39:6:39:21 | ...[...] | provenance | | nodes | test.ps1:1:1:1:3 | [post] a [f] | semmle.label | [post] a [f] | | test.ps1:1:8:1:18 | Source | semmle.label | Source | @@ -287,6 +293,13 @@ nodes | test.ps1:31:6:31:22 | ...[...] [element 3] | semmle.label | ...[...] [element 3] | | test.ps1:31:6:31:22 | ...[...] [element 4] | semmle.label | ...[...] [element 4] | | test.ps1:31:6:31:33 | ...[...] | semmle.label | ...[...] | +| test.ps1:33:6:33:17 | Source | semmle.label | Source | +| test.ps1:35:9:35:17 | ...,... [element 2] | semmle.label | ...,... [element 2] | +| test.ps1:35:15:35:17 | x | semmle.label | x | +| test.ps1:38:6:38:11 | arr8 [element 2] | semmle.label | arr8 [element 2] | +| test.ps1:38:6:38:14 | ...[...] | semmle.label | ...[...] | +| test.ps1:39:6:39:11 | arr8 [element 2] | semmle.label | arr8 [element 2] | +| test.ps1:39:6:39:21 | ...[...] | semmle.label | ...[...] | subpaths testFailures #select @@ -299,3 +312,5 @@ testFailures | test.ps1:26:6:26:25 | ...[...] | test.ps1:25:23:25:33 | Source | test.ps1:26:6:26:25 | ...[...] | $@ | test.ps1:25:23:25:33 | Source | Source | | test.ps1:30:6:30:17 | ...[...] | test.ps1:29:31:29:41 | Source | test.ps1:30:6:30:17 | ...[...] | $@ | test.ps1:29:31:29:41 | Source | Source | | test.ps1:31:6:31:33 | ...[...] | test.ps1:29:31:29:41 | Source | test.ps1:31:6:31:33 | ...[...] | $@ | test.ps1:29:31:29:41 | Source | Source | +| test.ps1:38:6:38:14 | ...[...] | test.ps1:33:6:33:17 | Source | test.ps1:38:6:38:14 | ...[...] | $@ | test.ps1:33:6:33:17 | Source | Source | +| test.ps1:39:6:39:21 | ...[...] | test.ps1:33:6:33:17 | Source | test.ps1:39:6:39:21 | ...[...] | $@ | test.ps1:33:6:33:17 | Source | Source | diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 index 6b480820c5b..f235c96e948 100644 --- a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 +++ b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 @@ -35,8 +35,8 @@ $x = Source "10" $arr8 = 0, 1, $x Sink $arr8[0] # clean Sink $arr8[1] # clean -Sink $arr8[2] # $ MISSING: hasValueFlow=10 -Sink $arr8[$unknown] # MISSING: hasValueFlow=10 +Sink $arr8[2] # $ hasValueFlow=10 +Sink $arr8[$unknown] # $ hasValueFlow=10 $y = Source "11"