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
4 changes: 3 additions & 1 deletion ql/lib/codeql-pack.lock.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ dependencies:
version: 1.0.12
codeql/ssa:
version: 1.0.12
codeql/threat-models:
version: 1.0.25
codeql/typetracking:
version: 1.0.12
codeql/util:
version: 1.0.12
codeql/yaml:
version: 1.0.23
version: 1.0.25
compiled: false
16 changes: 16 additions & 0 deletions ql/lib/codeql/bicep/DataFlow.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Provides classes for performing local (intra-procedural) and
* global (inter-procedural) data flow analyses.
*/

import codeql.Locations

/**
* Provides classes for performing local (intra-procedural) and
* global (inter-procedural) data flow analyses.
*/
module DataFlow {
private import codeql.dataflow.DataFlow
import DataFlowMake<Location, BicepDataFlow>
import Public
}
2 changes: 2 additions & 0 deletions ql/lib/codeql/bicep/ast/Resources.qll
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ class Resource extends TResource {

Identifier getIdentifier() { result = resource.getIdentifier() }

ResourceDeclaration getResourceDeclaration() { result = resource }

string getName() {
exists(StringLiteral name |
name = resource.getProperty("name") and
Expand Down
4 changes: 3 additions & 1 deletion ql/lib/codeql/bicep/ast/Stmts.qll
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ class UserDefinedFunction extends AstNode instanceof UserDefinedFunctionImpl {
*/
class Parameter extends AstNode instanceof ParameterImpl {
/** Gets the name of the parameter. */
Idents getName() { result = ParameterImpl.super.getName() }
Idents getIdentifier() { result = ParameterImpl.super.getName() }

string getName() { result = this.getIdentifier().getName() }

/** Gets the type of the parameter. */
Type getType() { result = ParameterImpl.super.getType() }
Expand Down
212 changes: 203 additions & 9 deletions ql/lib/codeql/bicep/ast/Variables.qll
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/**
* Bicep variable declarations.
*/

private import bicep
private import AstNodes
private import Calls
private import Idents
private import Stmts
private import codeql.bicep.controlflow.BasicBlocks as BasicBlocks
Expand All @@ -14,13 +16,205 @@ private import internal.VariableDeclaration
* A VariableDeclaration unknown AST node.
*/
class VariableDeclaration extends AstNode instanceof VariableDeclarationImpl {
/**
* Gets the identifier of the variable declaration.
*/
Idents getIdentifier() { result = VariableDeclarationImpl.super.getIdentifier() }

/**
* Gets the initializer expression of the variable declaration.
*/
Expr getInitializer() { result = VariableDeclarationImpl.super.getInitializer() }
/**
* Gets the identifier of the variable declaration.
*/
Idents getIdentifier() { result = VariableDeclarationImpl.super.getIdentifier() }

/**
* Gets the initializer expression of the variable declaration.
*/
Expr getInitializer() { result = VariableDeclarationImpl.super.getInitializer() }
}

private predicate variableDecl(AstNode node, string name) {
exists(ParameterDeclaration param |
param.getName() = name and
node = param
)
or
exists(VariableDeclaration vardelc |
vardelc.getIdentifier().getName() = name and
node = vardelc
)
or
exists(Resource resource |
resource.getIdentifier().getName() = name and
node = resource.getResourceDeclaration()
)
or
exists(OutputDeclaration output |
output.getIdentifier().getName() = name and
node = output
)
}

/**
* Variable represents a variable defination.
*/
class Variable extends MkVariable {
private AstNode node;
private string name;

Variable() { this = MkVariable(node, name) }

string getName() { result = name }

string toString() { result = "Variable[" + name + "]" }

AstNode getAstNode() { result = node }

/**
* Get the location of this variable.
*/
Location getLocation() { result = node.getLocation() }

/**
* Geta the inner variable of this variable.
*/
VariableAccess getAnAccess() { result.getVariable() = this }

/**
* Gets the type of this variable, if any.
*/
Type getType() {
result = this.getParameter().getType()
or
result = this.getOutput().getType()
}

/**
* Gets the parameter of this variable, if any.
*/
ParameterDeclaration getParameter() {
exists(ParameterDeclaration param |
param.getName() = this.getName() and
param.getEnclosingCfgScope() = this.getEnclosingCfgScope() and
result = param
)
}

/**
* Gets the variable declaration of this variable, if any.
*/
OutputDeclaration getOutput() {
exists(OutputDeclaration output |
output.getIdentifier().getName() = this.getName() and
output.getEnclosingCfgScope() = this.getEnclosingCfgScope() and
result = output
)
}

/**
* Gets the enclosing scope of this variable, if any.
*/
CfgScope getEnclosingCfgScope() { result = node.getEnclosingCfgScope() }

// Expr getInitializer() { }
string getAPrimaryQlClass() { result = "Variable" }
}

private predicate access(AstNode node, Variable v, string name) {
exists(Identifier ident |
ident.getName() = name and
// Make sure they are not in a declare statement
not ident.getParent() instanceof VariableDeclaration and
// not ident.getParent() instanceof ParameterDeclaration and
// not ident.getParent() instanceof OutputDeclaration and
// Make sure they are in the same scope
ident.getName() = v.getName() and
ident.getEnclosingCfgScope() = v.getEnclosingCfgScope() and
ident = node
)
}

/**
* VariableAccess is a class that represents the access to a variable.
*/
class VariableAccess extends MkVariableAccess, TVariableAccess {
private string name;
private AstNode node;
private Variable v;

VariableAccess() { this = MkVariableAccess(node, v, name) }

string getName() { result = name }

AstNode getAstNode() { result = node }

Variable getVariable() { result = v }

string toString() { result = "VariableAccess[" + name + "]" }

/**
* Get the location of this variable.
*/
Location getLocation() { result = node.getLocation() }

/**
* Gets the type of this variable, if any.
*/
Type getType() { result = this.getVariable().getType() }

/**
* Gets the enclosing scope of this variable, if any.
*/
CfgScope getEnclosingCfgScope() { result = v.getEnclosingCfgScope() }

string getAPrimaryQlClass() { result = "VariableAccess" }
}

class VariableWriteAccess extends VariableAccess {
VariableWriteAccess() {
// Parameter
this.getAstNode().getParent() instanceof ParameterDeclaration
or
// SET
this.getAstNode().getParent() instanceof VariableDeclaration
or
this.getAstNode().getParent() instanceof ResourceDeclaration
or
// Output
this.getAstNode().getParent() instanceof OutputDeclaration
}

override string getAPrimaryQlClass() { result = "VariableWrite" }
}

class VariableReadAccess extends VariableAccess {
VariableReadAccess() { not this instanceof VariableWriteAccess }

override string getAPrimaryQlClass() { result = "VariableRead" }
}

/**
* Holds if the variable is written too.
*/
// private predicate variableWrite(Variable node) {
// exists(Parameter param |
// param.getName() = node.getName() and
// param.getEnclosingCfgScope() = node.getEnclosingCfgScope()
// )
// }
cached
private module Cached {
cached
newtype TVariable =
TResource(Resource resource, string name) { resource.getIdentifier().getName() = name } or
TVariableDecl(VariableDeclaration varDecl, string name) {
varDecl.getIdentifier().getName() = name
} or
TParameter(ParameterDeclaration param, string name) { param.getName() = name } or
TOutput(OutputDeclaration output, string name) { output.getIdentifier().getName() = name } or
MkVariable(AstNode definingNode, string name) { variableDecl(definingNode, name) }

cached
newtype TVariableAccess =
TIdent(Identifier ident, string name) { ident.getName() = name } or
MkVariableAccess(AstNode node, Variable v, string name) { variableAccess(node, v, name) }

cached
predicate variableAccess(AstNode node, Variable v, string name) { access(node, v, name) }
}

private import Cached
5 changes: 5 additions & 0 deletions ql/lib/codeql/bicep/dataflow/DataFlow.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
private import codeql.dataflow.DataFlow
private import codeql.bicep.AST
private import codeql.bicep.CFG as Cfg
private import codeql.bicep.dataflow.Ssa as Ssa
private import codeql.Locations
42 changes: 42 additions & 0 deletions ql/lib/codeql/bicep/dataflow/Ssa.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Provides the module `Ssa` for working with static single assignment (SSA) form.
*/

/**
* Provides classes for working with static single assignment (SSA) form.
*/
module Ssa {
private import bicep
private import codeql.bicep.controlflow.BasicBlocks
private import codeql.bicep.controlflow.ControlFlowGraph
private import codeql.bicep.controlflow.internal.ControlFlowGraphImpl as CfgImpl
private import internal.SsaImpl as SsaImpl

class Variable = SsaImpl::SsaInput::SourceVariable;

class Definition extends SsaImpl::Definition {
final CfgNode getControlFlowNode() {
exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i))
}

final CfgNode getARead() { result = SsaImpl::getARead(this) }

final CfgNode getAFirstRead() { SsaImpl::firstRead(this, result) }
}

class WriteDefinition extends Definition, SsaImpl::WriteDefinition {
final CfgNode getControlFlowNode() {
exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i))
}

final CfgNode getARead() { result = SsaImpl::getARead(this) }

cached
override Location getLocation() {
exists(BasicBlock bb, int i |
this.definesAt(_, bb, i) and
result = bb.getNode(i).getLocation()
)
}
}
}
Loading