Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll
Original file line number Diff line number Diff line change
Expand Up @@ -527,13 +527,25 @@ module API {
pred = MkNamespaceOfTypeNameNode(typeName) and
succ = getForwardStartNode(typeName)
)
// or
// TODO: Handle getAMember when the predecessor is a MkUsingNode?
or
pred = MkRoot() and
exists(DataFlow::AutomaticVariableNode automatic |
automatic.getName() = name and
succ = getForwardStartNode(automatic)
)
or
exists(MemberExprReadAccess read |
read.getMemberName().toLowerCase() = name and
pred = getForwardEndNode(getALocalSourceStrict(getNodeFromExpr(read.getQualifier()))) and
succ = getForwardStartNode(getNodeFromExpr(read))
)
}

cached
predicate methodEdge(Node pred, string name, Node succ) {
exists(DataFlow::CallNode call | succ = MkMethodAccessNode(call) and name = call.getName() |
exists(DataFlow::CallNode call |
succ = MkMethodAccessNode(call) and name = call.getName().toLowerCase()
|
pred = getForwardEndNode(getALocalSourceStrict(call.getQualifier()))
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ newtype ChildIndex =
// hasMemberInType(_, _, i, _)
} or
ThisVar() or
PipelineParamVar() or
PipelineByPropertyNameVar(Raw::PipelineByPropertyNameParameter p) or
PipelineIteratorVar() or
PipelineByPropertyNameIteratorVar(Raw::PipelineByPropertyNameParameter p) or
RealVar(string name) { name = variableNameInScope(_, _) } or
Expand Down Expand Up @@ -85,9 +83,6 @@ string stringOfChildIndex(ChildIndex i) {
i = ThisVar() and
result = "ThisVar"
or
i = PipelineParamVar() and
result = "PipelineParamVar"
or
i = PipelineIteratorVar() and
result = "PipelineIteratorVar"
or
Expand Down
54 changes: 40 additions & 14 deletions powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,49 @@ class Parameter extends Variable instanceof ParameterImpl {

class ThisParameter extends Parameter instanceof ThisParameterImpl { }

class PipelineParameter extends Parameter {
PipelineParameter() { any(Synthesis s).isPipelineParameter(this) }
/** The pipeline parameter of a function. */
class PipelineParameter extends Parameter instanceof PipelineParameterImpl {
ScriptBlock getScriptBlock() { result = super.getScriptBlock() }
}

class PipelineByPropertyNameParameter extends Parameter {
PipelineByPropertyNameParameter() {
exists(NamedAttributeArgument namedAttribute |
this.getAnAttribute().(Attribute).getANamedArgument() = namedAttribute and
namedAttribute.getName().toLowerCase() = "valuefrompipelinebypropertyname"
|
namedAttribute.getValue().getValue().asBoolean() = true
or
not exists(namedAttribute.getValue().getValue().asBoolean())
)
}
/**
* The iterator variable associated with a pipeline parameter.
*
* This is the variable that is bound to the current element in the pipeline.
*/
class PipelineIteratorVariable extends Variable instanceof PipelineIteratorVariableImpl {
ProcessBlock getProcessBlock() { result = super.getProcessBlock() }
}

/**
* A pipeline-by-property-name parameter of a function.
*/
class PipelineByPropertyNameParameter extends Parameter instanceof PipelineByPropertyNameParameterImpl
{
ScriptBlock getScriptBlock() { result = super.getScriptBlock() }

string getPropertyName() { result = this.getName() }
string getPropertyName() { result = super.getName() }

/**
* Gets the iterator variable that is used to iterate over the elements in the pipeline.
*/
PipelineByPropertyNameIteratorVariable getIteratorVariable() { result.getParameter() = this }
}

/**
* The iterator variable associated with a pipeline-by-property-name parameter.
*
* This is the variable that is bound to the current element in the pipeline.
*/
class PipelineByPropertyNameIteratorVariable extends Variable instanceof PipelineByPropertyNameIteratorVariableImpl
{
ProcessBlock getProcessBlock() { result = super.getProcessBlock() }

string getPropertyName() { result = super.getPropertyName() }

/**
* Gets the pipeline-by-property-name parameter that this variable
* iterates over.
*/
PipelineByPropertyNameParameter getParameter() { result = super.getParameter() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,7 @@ class ScriptBlock extends Ast, TScriptBlock {
)
}

Parameter getParameter(int i) {
synthChild(getRawAst(this), funParam(i), result)
or
any(Synthesis s).pipelineParameterHasIndex(this, i) and
synthChild(getRawAst(this), PipelineParamVar(), result)
}
Parameter getParameter(int i) { synthChild(getRawAst(this), funParam(i), result) }

Parameter getThisParameter() { synthChild(getRawAst(this), ThisVar(), result) }

Expand Down
129 changes: 65 additions & 64 deletions powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ private import AutomaticVariable
newtype VarKind =
ThisVarKind() or
ParamVarRealKind() or
ParamVarPipelineKind() or
PipelineIteratorKind() or
PipelineByPropertyNameIteratorKind(string name) {
exists(Raw::ProcessBlock pb |
Expand Down Expand Up @@ -78,9 +77,7 @@ class Synthesis extends TSynthesis {

predicate parameterStaticType(Parameter p, string type) { none() }

predicate isPipelineParameter(Parameter p) { none() }

predicate pipelineParameterHasIndex(ScriptBlock s, int i) { none() }
predicate pipelineParameterHasIndex(Raw::ScriptBlock s, int i) { none() }

predicate functionName(FunctionBase f, string name) { none() }

Expand Down Expand Up @@ -167,33 +164,28 @@ private module SetVariableAssignment {
}
}

/** Gets the pipeline parameter associated with `s`. */
TVariable getPipelineParameter(Raw::ScriptBlock s) {
exists(ChildIndex i |
any(ParameterSynth::ParameterSynth ps).isPipelineParameterChild(s, _, i, _, _) and
result = TVariableSynth(s, i)
)
}

/**
* Syntesize parameters from parameter blocks and function definitions
* so that they have a uniform API.
*/
private module ParameterSynth {
private class ParameterSynth extends Synthesis {
class ParameterSynth extends Synthesis {
final override predicate isRelevant(Raw::Ast a) { a = any(Scope::Range r).getAParameter() }

private predicate parameter(
Raw::Ast parent, ChildIndex i, Raw::Parameter p, Child child, boolean isPipelineParameter
) {
private predicate parameter(Raw::Ast parent, ChildIndex i, Raw::Parameter p, Child child) {
exists(Scope::Range r, int index |
p = r.getParameter(index) and
parent = r and
i = funParam(index) and
child = SynthChild(VarSynthKind(ParamVarRealKind())) and
if p instanceof Raw::PipelineParameter
then isPipelineParameter = true
else isPipelineParameter = false
)
}

final override predicate isPipelineParameter(Parameter p) {
exists(Raw::Ast parent, ChildIndex i |
parent = getRawAst(p.getFunction().getBody()) and
this.isPipelineParameterChild(parent, _, i) and
p = TVariableSynth(parent, i)
child = SynthChild(VarSynthKind(ParamVarRealKind()))
)
}

Expand All @@ -205,47 +197,49 @@ private module ParameterSynth {
}

final override predicate variableSynthName(VariableSynth v, string name) {
exists(Raw::Ast parent, int i, Raw::Parameter p |
this.parameter(parent, FunParam(i), p, _, false) and
v = TVariableSynth(parent, FunParam(i)) and
name = p.getName()
)
or
exists(Raw::Ast parent |
this.child(parent, PipelineParamVar(), _) and
v = TVariableSynth(parent, PipelineParamVar()) and
exists(Raw::Ast parent, ChildIndex i | v = TVariableSynth(parent, i) |
exists(Raw::Parameter p |
this.parameter(parent, i, p, _) and
name = p.getName()
)
or
this.isPipelineParameterChild(parent, _, i, _, true) and
name = "[synth] pipeline"
)
}

private predicate isPipelineParameterChild(Raw::Ast parent, int index, ChildIndex i) {
exists(Scope::Range r | parent = r and i = PipelineParamVar() |
r.getParameter(index) instanceof Raw::PipelineParameter
predicate isPipelineParameterChild(
Raw::Ast parent, int index, ChildIndex i, Child child, boolean synthesized
) {
exists(Scope::Range r |
parent = r and
i = funParam(index) and
child = SynthChild(VarSynthKind(ParamVarRealKind()))
|
r.getParameter(index) instanceof Raw::PipelineParameter and
synthesized = false
or
not r.getAParameter() instanceof Raw::PipelineParameter and
index = synthPipelineParameterChildIndex(r)
index = synthPipelineParameterChildIndex(r) and
synthesized = true
)
}

final override predicate pipelineParameterHasIndex(ScriptBlock s, int i) {
exists(Raw::ScriptBlock scriptBlock |
s = TScriptBlock(scriptBlock) and
this.isPipelineParameterChild(scriptBlock, i, _)
)
final override predicate pipelineParameterHasIndex(Raw::ScriptBlock s, int i) {
this.isPipelineParameterChild(s, i, _, _, _)
}

final override predicate child(Raw::Ast parent, ChildIndex i, Child child) {
// Synthesize parameters
this.parameter(parent, i, _, child, false)
this.parameter(parent, i, _, child)
or
// Synthesize pipeline parameter
child = SynthChild(VarSynthKind(ParamVarPipelineKind())) and
this.isPipelineParameterChild(parent, _, i)
// Synthesize implicit pipeline parameter, if necessary
this.isPipelineParameterChild(parent, _, i, child, true)
or
// Synthesize default values
exists(Raw::Parameter q |
parent = q and
this.parameter(_, _, q, _, _)
this.parameter(_, _, q, _)
|
i = paramDefaultVal() and
child = childRef(getResultAst(q.getDefaultValue()))
Expand All @@ -258,30 +252,30 @@ private module ParameterSynth {
}

final override Parameter getResultAstImpl(Raw::Ast r) {
exists(Raw::Ast parent, int i |
this.parameter(parent, FunParam(i), r, _, false) and
result = TVariableSynth(parent, FunParam(i))
)
or
exists(Scope::Range scope, int i, ChildIndex index |
scope.getParameter(i) = r and
this.isPipelineParameterChild(scope, i, index) and
result = TVariableSynth(scope, index)
exists(Raw::Ast parent, ChildIndex i |
this.parameter(parent, i, r, _) and
result = TVariableSynth(parent, i)
)
}

final override Location getLocation(Ast n) {
exists(Raw::Ast parent, Raw::Parameter p, int i |
this.parameter(parent, _, p, _, _) and
n = TVariableSynth(parent, FunParam(i)) and
result = p.getLocation()
exists(Raw::Ast parent, ChildIndex i | n = TVariableSynth(parent, i) |
exists(Raw::Parameter p |
this.parameter(parent, i, p, _) and
result = p.getLocation()
)
or
this.isPipelineParameterChild(parent, _, i, _, true) and
result = parent.getLocation()
)
}

final override predicate parameterStaticType(Parameter n, string type) {
exists(Raw::Ast parent, int i, Raw::Parameter p |
this.parameter(parent, FunParam(i), p, _, false) and
n = TVariableSynth(parent, FunParam(i)) and
exists(Raw::Ast parent, Raw::Parameter p, ChildIndex i |
// No need to consider the synthesized pipeline parameter as it never
// has a static type.
this.parameter(parent, i, p, _) and
n = TVariableSynth(parent, i) and
type = p.getStaticType()
)
}
Expand Down Expand Up @@ -440,6 +434,11 @@ private module FunctionSynth {
n = TFunctionSynth(fundefStmt, _) and
result = fundefStmt.getLocation()
)
or
exists(Raw::TopLevelScriptBlock topLevelScriptBlock |
n = TTopLevelFunction(topLevelScriptBlock) and
result = topLevelScriptBlock.getLocation()
)
}
}
}
Expand Down Expand Up @@ -857,8 +856,10 @@ private module IteratorAccessSynth {
result = cmdExpr.getLocation()
)
or
exists(Raw::Ast parent |
n = TVariableSynth(parent, _) and
exists(Raw::Ast parent, ChildIndex i |
i instanceof PipelineIteratorVar or i instanceof PipelineByPropertyNameIteratorVar
|
n = TVariableSynth(parent, i) and
result = parent.getLocation()
)
}
Expand All @@ -870,12 +871,12 @@ private module PipelineAccess {
final override predicate child(Raw::Ast parent, ChildIndex i, Child child) {
exists(Raw::ProcessBlock pb | parent = pb |
i = processBlockPipelineVarReadAccess() and
exists(PipelineVariable pipelineVar |
pipelineVar = TVariableSynth(pb.getScriptBlock(), PipelineParamVar()) and
exists(PipelineParameter pipelineVar |
pipelineVar = getPipelineParameter(pb.getScriptBlock()) and
child = SynthChild(VarAccessSynthKind(pipelineVar))
)
or
exists(PipelineByPropertyNameVariable pipelineVar, Raw::PipelineByPropertyNameParameter p |
exists(PipelineByPropertyNameParameter pipelineVar, Raw::PipelineByPropertyNameParameter p |
i = processBlockPipelineByPropertyNameVarReadAccess(p.getName()) and
getResultAst(p) = pipelineVar and
child = SynthChild(VarAccessSynthKind(pipelineVar))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ class TypeNameExpr extends Expr, TTypeNameExpr {
override string toString() { result = this.getName() }

predicate isQualified() { this.getNamespace() != "" }

predicate hasQualifiedName(string namespace, string typename) {
this.isQualified() and
this.parseName(namespace, typename)
}
}

class QualifiedTypeNameExpr extends TypeNameExpr {
Expand Down
Loading
Loading