Skip to content

Commit 0fb75af

Browse files
authored
Merge pull request #137 from microsoft/powershell-taint-through-string-interpolation
PS: Taint-flow through string interpolation
2 parents 16aacd8 + f16b2cb commit 0fb75af

File tree

6 files changed

+57
-12
lines changed

6 files changed

+57
-12
lines changed

powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,22 @@ module ExprNodes {
565565

566566
final ExprCfgNode getAnOperand() { e.hasCfgChild(this.getExpr().getAnOperand(), this, result) }
567567
}
568+
569+
class ExpandableStringChildMappinig extends ExprChildMapping, ExpandableStringExpr {
570+
override predicate relevantChild(Ast n) { n = this.getAnExpr() }
571+
}
572+
573+
class ExpandableStringCfgNode extends ExprCfgNode {
574+
override string getAPrimaryQlClass() { result = "ExpandableStringCfgNode" }
575+
576+
override ExpandableStringChildMappinig e;
577+
578+
override ExpandableStringExpr getExpr() { result = e }
579+
580+
ExprCfgNode getExpr(int i) { e.hasCfgChild(e.getExpr(i), this, result) }
581+
582+
ExprCfgNode getAnExpr() { result = this.getExpr(_) }
583+
}
568584
}
569585

570586
module StmtNodes {

powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,9 @@ class CallNode extends AstNode {
469469

470470
/** A call to operator `&`, viwed as a node in a data flow graph. */
471471
class CallOperatorNode extends CallNode {
472-
CallOperatorNode() { this.getCallNode() instanceof CfgNodes::StmtNodes::CallOperatorCfgNode }
472+
override CfgNodes::StmtNodes::CallOperatorCfgNode call;
473+
474+
Node getCommand() { result.asExpr() = call.getCommand() }
473475
}
474476

475477
/** A use of a type name, viewed as a node in a data flow graph. */

powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,18 @@ private module Cached {
3434
cached
3535
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
3636
(
37+
// Flow from an operand to an operation
3738
exists(CfgNodes::ExprNodes::OperationCfgNode op |
3839
op = nodeTo.asExpr() and
3940
op.getAnOperand() = nodeFrom.asExpr()
4041
)
4142
or
43+
// Flow through string interpolation
44+
exists(CfgNodes::ExprNodes::ExpandableStringCfgNode es |
45+
nodeFrom.asExpr() = es.getAnExpr() and
46+
nodeTo.asExpr() = es
47+
)
48+
or
4249
// Although flow through collections is modeled precisely using stores/reads, we still
4350
// allow flow out of a _tainted_ collection. This is needed in order to support taint-
4451
// tracking configurations where the source is a collection.

powershell/ql/test/library-tests/dataflow/local/flow.expected

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
| test.ps1:1:7:1:13 | call to Source | test.ps1:1:1:1:13 | ...=... |
44
| test.ps1:2:1:2:9 | call to Sink | test.ps1:2:1:2:9 | pre-return value for call to Sink |
55
| test.ps1:2:1:2:9 | call to Sink | test.ps1:2:1:2:9 | pre-return value for call to Sink |
6-
| test.ps1:2:1:2:9 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
6+
| test.ps1:2:1:2:9 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
77
| test.ps1:2:1:2:9 | pre-return value for call to Sink | test.ps1:2:1:2:9 | implicit unwrapping of call to Sink |
88
| test.ps1:4:1:4:3 | b | test.ps1:5:4:5:6 | b |
99
| test.ps1:4:6:4:13 | call to GetBool | test.ps1:4:1:4:3 | b |
@@ -14,7 +14,7 @@
1414
| test.ps1:6:11:6:17 | call to Source | test.ps1:6:5:6:17 | ...=... |
1515
| test.ps1:8:1:8:9 | call to Sink | test.ps1:8:1:8:9 | pre-return value for call to Sink |
1616
| test.ps1:8:1:8:9 | call to Sink | test.ps1:8:1:8:9 | pre-return value for call to Sink |
17-
| test.ps1:8:1:8:9 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
17+
| test.ps1:8:1:8:9 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
1818
| test.ps1:8:1:8:9 | pre-return value for call to Sink | test.ps1:8:1:8:9 | implicit unwrapping of call to Sink |
1919
| test.ps1:10:1:10:3 | c | test.ps1:11:6:11:8 | c |
2020
| test.ps1:10:6:10:16 | [...]... | test.ps1:10:1:10:3 | c |
@@ -23,7 +23,7 @@
2323
| test.ps1:10:14:10:16 | b | test.ps1:10:6:10:16 | [...]... |
2424
| test.ps1:11:1:11:8 | call to Sink | test.ps1:11:1:11:8 | pre-return value for call to Sink |
2525
| test.ps1:11:1:11:8 | call to Sink | test.ps1:11:1:11:8 | pre-return value for call to Sink |
26-
| test.ps1:11:1:11:8 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
26+
| test.ps1:11:1:11:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
2727
| test.ps1:11:1:11:8 | pre-return value for call to Sink | test.ps1:11:1:11:8 | implicit unwrapping of call to Sink |
2828
| test.ps1:11:6:11:8 | [post] c | test.ps1:13:7:13:9 | c |
2929
| test.ps1:11:6:11:8 | c | test.ps1:13:7:13:9 | c |
@@ -35,7 +35,7 @@
3535
| test.ps1:13:7:13:9 | c | test.ps1:13:7:13:9 | c |
3636
| test.ps1:14:1:14:8 | call to Sink | test.ps1:14:1:14:8 | pre-return value for call to Sink |
3737
| test.ps1:14:1:14:8 | call to Sink | test.ps1:14:1:14:8 | pre-return value for call to Sink |
38-
| test.ps1:14:1:14:8 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
38+
| test.ps1:14:1:14:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
3939
| test.ps1:14:1:14:8 | pre-return value for call to Sink | test.ps1:14:1:14:8 | implicit unwrapping of call to Sink |
4040
| test.ps1:14:6:14:8 | [post] d | test.ps1:16:6:16:8 | d |
4141
| test.ps1:14:6:14:8 | d | test.ps1:16:6:16:8 | d |
@@ -45,5 +45,12 @@
4545
| test.ps1:16:6:16:12 | ...+... | test.ps1:16:6:16:12 | ...+... |
4646
| test.ps1:17:1:17:8 | call to Sink | test.ps1:17:1:17:8 | pre-return value for call to Sink |
4747
| test.ps1:17:1:17:8 | call to Sink | test.ps1:17:1:17:8 | pre-return value for call to Sink |
48-
| test.ps1:17:1:17:8 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
48+
| test.ps1:17:1:17:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
4949
| test.ps1:17:1:17:8 | pre-return value for call to Sink | test.ps1:17:1:17:8 | implicit unwrapping of call to Sink |
50+
| test.ps1:19:1:19:3 | f | test.ps1:21:25:21:27 | f |
51+
| test.ps1:19:6:19:12 | call to Source | test.ps1:19:1:19:3 | f |
52+
| test.ps1:19:6:19:12 | call to Source | test.ps1:19:1:19:12 | ...=... |
53+
| test.ps1:21:1:21:28 | call to Sink | test.ps1:21:1:21:28 | pre-return value for call to Sink |
54+
| test.ps1:21:1:21:28 | call to Sink | test.ps1:21:1:21:28 | pre-return value for call to Sink |
55+
| test.ps1:21:1:21:28 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
56+
| test.ps1:21:1:21:28 | pre-return value for call to Sink | test.ps1:21:1:21:28 | implicit unwrapping of call to Sink |

powershell/ql/test/library-tests/dataflow/local/taint.expected

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
| test.ps1:1:7:1:13 | call to Source | test.ps1:1:1:1:13 | ...=... |
44
| test.ps1:2:1:2:9 | call to Sink | test.ps1:2:1:2:9 | pre-return value for call to Sink |
55
| test.ps1:2:1:2:9 | call to Sink | test.ps1:2:1:2:9 | pre-return value for call to Sink |
6-
| test.ps1:2:1:2:9 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
6+
| test.ps1:2:1:2:9 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
77
| test.ps1:2:1:2:9 | pre-return value for call to Sink | test.ps1:2:1:2:9 | implicit unwrapping of call to Sink |
88
| test.ps1:2:1:2:9 | pre-return value for call to Sink | test.ps1:2:1:2:9 | implicit unwrapping of call to Sink |
99
| test.ps1:4:1:4:3 | b | test.ps1:5:4:5:6 | b |
@@ -15,7 +15,7 @@
1515
| test.ps1:6:11:6:17 | call to Source | test.ps1:6:5:6:17 | ...=... |
1616
| test.ps1:8:1:8:9 | call to Sink | test.ps1:8:1:8:9 | pre-return value for call to Sink |
1717
| test.ps1:8:1:8:9 | call to Sink | test.ps1:8:1:8:9 | pre-return value for call to Sink |
18-
| test.ps1:8:1:8:9 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
18+
| test.ps1:8:1:8:9 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
1919
| test.ps1:8:1:8:9 | pre-return value for call to Sink | test.ps1:8:1:8:9 | implicit unwrapping of call to Sink |
2020
| test.ps1:8:1:8:9 | pre-return value for call to Sink | test.ps1:8:1:8:9 | implicit unwrapping of call to Sink |
2121
| test.ps1:10:1:10:3 | c | test.ps1:11:6:11:8 | c |
@@ -25,7 +25,7 @@
2525
| test.ps1:10:14:10:16 | b | test.ps1:10:6:10:16 | [...]... |
2626
| test.ps1:11:1:11:8 | call to Sink | test.ps1:11:1:11:8 | pre-return value for call to Sink |
2727
| test.ps1:11:1:11:8 | call to Sink | test.ps1:11:1:11:8 | pre-return value for call to Sink |
28-
| test.ps1:11:1:11:8 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
28+
| test.ps1:11:1:11:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
2929
| test.ps1:11:1:11:8 | pre-return value for call to Sink | test.ps1:11:1:11:8 | implicit unwrapping of call to Sink |
3030
| test.ps1:11:1:11:8 | pre-return value for call to Sink | test.ps1:11:1:11:8 | implicit unwrapping of call to Sink |
3131
| test.ps1:11:6:11:8 | [post] c | test.ps1:13:7:13:9 | c |
@@ -38,7 +38,7 @@
3838
| test.ps1:13:7:13:9 | c | test.ps1:13:7:13:9 | c |
3939
| test.ps1:14:1:14:8 | call to Sink | test.ps1:14:1:14:8 | pre-return value for call to Sink |
4040
| test.ps1:14:1:14:8 | call to Sink | test.ps1:14:1:14:8 | pre-return value for call to Sink |
41-
| test.ps1:14:1:14:8 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
41+
| test.ps1:14:1:14:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
4242
| test.ps1:14:1:14:8 | pre-return value for call to Sink | test.ps1:14:1:14:8 | implicit unwrapping of call to Sink |
4343
| test.ps1:14:1:14:8 | pre-return value for call to Sink | test.ps1:14:1:14:8 | implicit unwrapping of call to Sink |
4444
| test.ps1:14:6:14:8 | [post] d | test.ps1:16:6:16:8 | d |
@@ -51,6 +51,15 @@
5151
| test.ps1:16:11:16:12 | 1 | test.ps1:16:6:16:12 | ...+... |
5252
| test.ps1:17:1:17:8 | call to Sink | test.ps1:17:1:17:8 | pre-return value for call to Sink |
5353
| test.ps1:17:1:17:8 | call to Sink | test.ps1:17:1:17:8 | pre-return value for call to Sink |
54-
| test.ps1:17:1:17:8 | implicit unwrapping of call to Sink | test.ps1:1:1:17:8 | return value for test.ps1 |
54+
| test.ps1:17:1:17:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
5555
| test.ps1:17:1:17:8 | pre-return value for call to Sink | test.ps1:17:1:17:8 | implicit unwrapping of call to Sink |
5656
| test.ps1:17:1:17:8 | pre-return value for call to Sink | test.ps1:17:1:17:8 | implicit unwrapping of call to Sink |
57+
| test.ps1:19:1:19:3 | f | test.ps1:21:25:21:27 | f |
58+
| test.ps1:19:6:19:12 | call to Source | test.ps1:19:1:19:3 | f |
59+
| test.ps1:19:6:19:12 | call to Source | test.ps1:19:1:19:12 | ...=... |
60+
| test.ps1:21:1:21:28 | call to Sink | test.ps1:21:1:21:28 | pre-return value for call to Sink |
61+
| test.ps1:21:1:21:28 | call to Sink | test.ps1:21:1:21:28 | pre-return value for call to Sink |
62+
| test.ps1:21:1:21:28 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 |
63+
| test.ps1:21:1:21:28 | pre-return value for call to Sink | test.ps1:21:1:21:28 | implicit unwrapping of call to Sink |
64+
| test.ps1:21:1:21:28 | pre-return value for call to Sink | test.ps1:21:1:21:28 | implicit unwrapping of call to Sink |
65+
| test.ps1:21:25:21:27 | f | test.ps1:21:6:21:28 | here is a string: $f |

powershell/ql/test/library-tests/dataflow/local/test.ps1

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ $d = ($c)
1414
Sink $d
1515

1616
$e = $d + 1
17-
Sink $e
17+
Sink $e
18+
19+
$f = Source
20+
21+
Sink "here is a string: $f"

0 commit comments

Comments
 (0)