Skip to content

Commit 6797f8f

Browse files
committed
PS: Add flow into, and out of, the new implicit unwrapping nodes.
1 parent 15a22e5 commit 6797f8f

File tree

7 files changed

+155
-7
lines changed

7 files changed

+155
-7
lines changed

powershell/ql/lib/powershell.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import semmle.code.powershell.Expression
77
import semmle.code.powershell.CommandBase
88
import semmle.code.powershell.AttributeBase
99
import semmle.code.powershell.PipelineBase
10+
import semmle.code.powershell.PipelineChain
1011
import semmle.code.powershell.BaseConstantExpression
1112
import semmle.code.powershell.ConstantExpression
1213
import semmle.code.powershell.MemberExpressionBase

powershell/ql/lib/semmle/code/powershell/Function.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ abstract private class AbstractFunction extends Ast {
5050
result = this.getBody().getParamBlock().getParameter(i)
5151
}
5252

53+
final Parameter getParameterExcludingPipline(int i) {
54+
result = this.getFunctionParameter(i)
55+
or
56+
result = this.getBody().getParamBlock().getParameterExcludingPipline(i)
57+
}
58+
5359
final Parameter getThisParameter() {
5460
result.isThis() and
5561
result.getFunction() = this
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import powershell
22

33
class NamedAttributeArgument extends @named_attribute_argument, Ast {
4-
final override string toString() { result = this.getValue().toString() }
4+
final override string toString() { result = this.getName() }
55

66
final override SourceLocation getLocation() { named_attribute_argument_location(this, result) }
77

88
string getName() { named_attribute_argument(this, result, _) }
99

1010
Expr getValue() { named_attribute_argument(this, _, result) }
1111
}
12+
13+
class ValueFromPipelineAttribute extends NamedAttributeArgument {
14+
ValueFromPipelineAttribute() { this.getName() = "ValueFromPipeline" }
15+
}

powershell/ql/lib/semmle/code/powershell/ParamBlock.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ class ParamBlock extends @param_block, Ast {
1515

1616
Parameter getParameter(int i) { result.hasParameterBlock(this, i) }
1717

18+
Parameter getParameterExcludingPipline(int i) { result.hasParameterBlockExcludingPipeline(this, i) }
19+
1820
Parameter getAParameter() { result = this.getParameter(_) }
1921
}

powershell/ql/lib/semmle/code/powershell/Variable.qll

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ private predicate hasParameterBlockImpl(Internal::Parameter p, ParamBlock block,
1010
param_block_parameter(block, i, p)
1111
}
1212

13+
private predicate hasParameterBlockExcludingPipelineImpl(
14+
Internal::Parameter p, ParamBlock block, int i
15+
) {
16+
p =
17+
rank[i + 1](Internal::Parameter cand, int j |
18+
hasParameterBlockImpl(cand, block, j) and
19+
not cand.getAnAttribute().(Attribute).getANamedArgument() instanceof
20+
ValueFromPipelineAttribute
21+
|
22+
cand order by j
23+
)
24+
}
25+
1326
/**
1427
* Gets the enclosing scope of `p`.
1528
*
@@ -56,10 +69,14 @@ private class ParameterImpl extends TParameterImpl {
5669

5770
predicate hasParameterBlock(ParamBlock block, int i) { none() }
5871

72+
predicate hasParameterBlockExcludingPipeline(ParamBlock block, int i) { none() }
73+
5974
predicate isFunctionParameter(Function f, int i) { none() }
6075

6176
Expr getDefaultValue() { none() }
6277

78+
abstract Attribute getAnAttribute();
79+
6380
VarAccess getAnAccess() {
6481
// TODO: This won't join order nicely.
6582
result.getUserPath() = this.getName() and
@@ -82,9 +99,15 @@ private class InternalParameter extends ParameterImpl, TInternalParameter {
8299
hasParameterBlockImpl(p, block, i)
83100
}
84101

102+
override predicate hasParameterBlockExcludingPipeline(ParamBlock block, int i) {
103+
hasParameterBlockExcludingPipelineImpl(p, block, i)
104+
}
105+
85106
override predicate isFunctionParameter(Function f, int i) { isFunctionParameterImpl(p, f, i) }
86107

87108
override Expr getDefaultValue() { result = p.getDefaultValue() }
109+
110+
override Attribute getAnAttribute() { result = p.getAnAttribute() }
88111
}
89112

90113
/**
@@ -113,6 +136,8 @@ private class Underscore extends ParameterImpl, TUnderscore {
113136
override string getName() { result = "_" }
114137

115138
final override Scope getEnclosingScope() { result = scope }
139+
140+
final override Attribute getAnAttribute() { none() }
116141
}
117142

118143
private class ThisParameter extends ParameterImpl, TThisParameter {
@@ -125,6 +150,8 @@ private class ThisParameter extends ParameterImpl, TThisParameter {
125150
override string getName() { result = "this" }
126151

127152
final override Scope getEnclosingScope() { result = scope }
153+
154+
final override Attribute getAnAttribute() { none() }
128155
}
129156

130157
private newtype TVariable =
@@ -199,6 +226,10 @@ class Parameter extends AbstractLocalScopeVariable, TParameter {
199226

200227
predicate hasParameterBlock(ParamBlock block, int i) { p.hasParameterBlock(block, i) }
201228

229+
predicate hasParameterBlockExcludingPipeline(ParamBlock block, int i) {
230+
p.hasParameterBlockExcludingPipeline(block, i)
231+
}
232+
202233
predicate isFunctionParameter(Function f, int i) { p.isFunctionParameter(f, i) }
203234

204235
Expr getDefaultValue() { result = p.getDefaultValue() }
@@ -215,11 +246,23 @@ class Parameter extends AbstractLocalScopeVariable, TParameter {
215246
*/
216247
int getIndex() { result = this.getFunctionIndex() or result = this.getBlockIndex() }
217248

249+
int getIndexExcludingPipeline() {
250+
result = this.getFunctionIndex() or result = this.getBlockIndexExcludingPipeline()
251+
}
252+
218253
/** Gets the index of this parameter in the parameter block, if any. */
219254
int getBlockIndex() { this.hasParameterBlock(_, result) }
220255

256+
int getBlockIndexExcludingPipeline() { this.hasParameterBlockExcludingPipeline(_, result) }
257+
221258
/** Gets the index of this parameter in the function, if any. */
222259
int getFunctionIndex() { this.isFunctionParameter(_, result) }
223260

224261
Function getFunction() { result.getBody() = this.getDeclaringScope() }
262+
263+
Attribute getAnAttribute() { result = p.getAnAttribute() }
264+
265+
predicate isPipeline() {
266+
this.getAnAttribute().getANamedArgument() instanceof ValueFromPipelineAttribute
267+
}
225268
}

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

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,20 +130,34 @@ abstract private class NonExprChildMapping extends ChildMapping {
130130
abstract private class AbstractCallCfgNode extends AstCfgNode {
131131
override string getAPrimaryQlClass() { result = "CfgCall" }
132132

133+
/** Holds if this call invokes a function with the name `name`. */
133134
final predicate hasName(string name) { this.getName() = name }
134135

136+
/** Gets the name of the function that is invoked by this call. */
135137
abstract string getName();
136138

139+
/** Gets the qualifier of this call, if any. */
137140
ExprCfgNode getQualifier() { none() }
138141

142+
/** Gets the i'th argument to this call. */
139143
abstract ExprCfgNode getArgument(int i);
140144

145+
/** Gets the i'th positional argument to this call. */
141146
abstract ExprCfgNode getPositionalArgument(int i);
142147

148+
/** Gets the argument with the name `name`, if any. */
143149
abstract ExprCfgNode getNamedArgument(string name);
144150

151+
/**
152+
* Gets any argument of this call.
153+
*
154+
* Note that this predicate doesn't get the pipeline argument, if any.
155+
*/
145156
abstract ExprCfgNode getAnArgument();
146157

158+
/**
159+
* Gets the expression that provides the call target of this call, if any.
160+
*/
147161
abstract ExprCfgNode getCommand();
148162
}
149163

@@ -381,12 +395,12 @@ module ExprNodes {
381395
}
382396

383397
module StmtNodes {
384-
private class CmdChildMapping extends NonExprChildMapping, Cmd {
398+
private class CmdChildMapping extends CmdBaseChildMapping, Cmd {
385399
override predicate relevantChild(Ast n) { n = this.getAnArgument() or n = this.getCommand() }
386400
}
387401

388402
/** A control-flow node that wraps a `Cmd` AST expression. */
389-
class CmdCfgNode extends StmtCfgNode, AbstractCallCfgNode {
403+
class CmdCfgNode extends CmdBaseCfgNode, AbstractCallCfgNode {
390404
override string getAPrimaryQlClass() { result = "CmdCfgNode" }
391405

392406
override CmdChildMapping s;
@@ -410,14 +424,14 @@ module StmtNodes {
410424
final override string getName() { result = s.getCmdName().getValue().getValue() }
411425
}
412426

413-
private class AssignStmtChildMapping extends NonExprChildMapping, AssignStmt {
427+
private class AssignStmtChildMapping extends PipelineBaseChildMapping, AssignStmt {
414428
override predicate relevantChild(Ast n) {
415429
n = this.getLeftHandSide() or n = this.getRightHandSide()
416430
}
417431
}
418432

419433
/** A control-flow node that wraps an `AssignStmt` AST expression. */
420-
class AssignStmtCfgNode extends StmtCfgNode {
434+
class AssignStmtCfgNode extends PipelineBaseCfgNode {
421435
override string getAPrimaryQlClass() { result = "AssignCfgNode" }
422436

423437
override AssignStmtChildMapping s;
@@ -431,12 +445,12 @@ module StmtNodes {
431445
final StmtCfgNode getRightHandSide() { s.hasCfgChild(s.getRightHandSide(), this, result) }
432446
}
433447

434-
class CmdExprChildMapping extends NonExprChildMapping, CmdExpr {
448+
class CmdExprChildMapping extends CmdBaseChildMapping, CmdExpr {
435449
override predicate relevantChild(Ast n) { n = this.getExpr() }
436450
}
437451

438452
/** A control-flow node that wraps a `CmdExpr` expression. */
439-
class CmdExprCfgNode extends StmtCfgNode {
453+
class CmdExprCfgNode extends CmdBaseCfgNode {
440454
override string getAPrimaryQlClass() { result = "CmdExprCfgNode" }
441455

442456
override CmdExprChildMapping s;
@@ -445,4 +459,70 @@ module StmtNodes {
445459

446460
final ExprCfgNode getExpr() { s.hasCfgChild(s.getExpr(), this, result) }
447461
}
462+
463+
class PipelineBaseChildMapping extends NonExprChildMapping, PipelineBase {
464+
override predicate relevantChild(Ast n) { none() }
465+
}
466+
467+
class PipelineBaseCfgNode extends StmtCfgNode {
468+
override string getAPrimaryQlClass() { result = "PipelineBaseCfgNode" }
469+
470+
override PipelineBaseChildMapping s;
471+
472+
override PipelineBase getStmt() { result = super.getStmt() }
473+
}
474+
475+
class ChainableChildMapping extends PipelineBaseChildMapping, Chainable {
476+
override predicate relevantChild(Ast n) { none() }
477+
}
478+
479+
class ChainableCfgNode extends PipelineBaseCfgNode {
480+
override string getAPrimaryQlClass() { result = "ChainableCfgNode" }
481+
482+
override ChainableChildMapping s;
483+
484+
override Chainable getStmt() { result = super.getStmt() }
485+
}
486+
487+
class PipelineChainChildMapping extends ChainableChildMapping, PipelineChain {
488+
override predicate relevantChild(Ast n) { n = this.getLeft() or n = this.getRight() }
489+
}
490+
491+
class PipelineChainCfgNode extends ChainableCfgNode {
492+
override string getAPrimaryQlClass() { result = "PipelineChainCfgNode" }
493+
494+
override PipelineChainChildMapping s;
495+
496+
override PipelineChain getStmt() { result = super.getStmt() }
497+
498+
final ChainableCfgNode getLeft() { s.hasCfgChild(s.getLeft(), this, result) }
499+
500+
final ChainableCfgNode getRight() { s.hasCfgChild(s.getRight(), this, result) }
501+
}
502+
503+
class CmdBaseChildMapping extends ChainableChildMapping, CmdBase { }
504+
505+
class CmdBaseCfgNode extends ChainableCfgNode {
506+
override string getAPrimaryQlClass() { result = "CmdBaseCfgNode" }
507+
508+
override CmdBaseChildMapping s;
509+
510+
override CmdBase getStmt() { result = super.getStmt() }
511+
}
512+
513+
class PipelineChildMapping extends ChainableChildMapping, Pipeline {
514+
override predicate relevantChild(Ast n) { n = this.getAComponent() }
515+
}
516+
517+
class PipelineCfgNode extends ChainableCfgNode {
518+
override string getAPrimaryQlClass() { result = "PipelineCfgNode" }
519+
520+
override PipelineChildMapping s;
521+
522+
override Pipeline getStmt() { result = super.getStmt() }
523+
524+
final CmdBaseCfgNode getComponent(int i) { s.hasCfgChild(s.getComponent(i), this, result) }
525+
526+
final CmdBaseCfgNode getAComponent() { s.hasCfgChild(s.getAComponent(), this, result) }
527+
}
448528
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ module LocalFlow {
9696
nodeFrom.asStmt() = nodeTo.asStmt().(CfgNodes::StmtNodes::AssignStmtCfgNode).getRightHandSide()
9797
or
9898
nodeFrom.asExpr() = nodeTo.asStmt().(CfgNodes::StmtNodes::CmdExprCfgNode).getExpr()
99+
or
100+
nodeFrom.(AstNode).getCfgNode() = nodeTo.(PreReturNodeImpl).getReturnedNode()
101+
or
102+
exists(CfgNode cfgNode |
103+
nodeFrom = TPreReturnNodeImpl(cfgNode, true) and
104+
nodeTo = TImplicitWrapNode(cfgNode, false)
105+
)
106+
or
107+
exists(CfgNode cfgNode |
108+
nodeFrom = TImplicitWrapNode(cfgNode, false) and
109+
nodeTo = TReturnNodeImpl(cfgNode.getScope())
110+
)
99111
}
100112

101113
predicate localMustFlowStep(Node nodeFrom, Node nodeTo) {

0 commit comments

Comments
 (0)