Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PS: Add AST and CFG classes for operator & and add environment variable reads as local flow sources #136

Merged
merged 3 commits into from
Nov 8, 2024
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
7 changes: 7 additions & 0 deletions powershell/ql/lib/semmle/code/powershell/Command.qll
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import powershell

private predicate parseCommandName(Cmd cmd, string namespace, string name) {
exists(string qualified | command(cmd, qualified, _, _, _) |
namespace = qualified.regexpCapture("([^\\\\]+)\\\\([^\\\\]+)", 1) and
Expand All @@ -11,6 +12,7 @@ private predicate parseCommandName(Cmd cmd, string namespace, string name) {
)
}

/** A call to a command. */
class Cmd extends @command, CmdBase {
override string toString() { result = "call to " + this.getQualifiedCommandName() }

Expand Down Expand Up @@ -88,3 +90,8 @@ class Cmd extends @command, CmdBase {

Redirection getARedirection() { result = this.getRedirection(_) }
}

/** A call to operator `&`. */
class CallOperator extends Cmd {
CallOperator() { this.getKind() = 28 }
}
15 changes: 15 additions & 0 deletions powershell/ql/lib/semmle/code/powershell/Variable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,21 @@ class LocalVariable extends AbstractLocalScopeVariable, TLocalVariable {
final override Scope getDeclaringScope() { result = scope }
}

/**
* A variable of the form `$Env:HOME`.
*/
class EnvVariable extends Variable {
string var;

EnvVariable() { this.getName() = ["env:", "Env:"] + var }

/**
* Gets the part of the variable name that represens which environment
* variable.
*/
string getEnvironmentVariable() { result = var }
}

class Parameter extends AbstractLocalScopeVariable, TParameter {
ParameterImpl p;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,12 @@ class VarWriteAccess extends VarAccess {

predicate isImplicit() { isImplicitVariableWriteAccess(this) }
}

/** An access to an environment variable such as `$Env:PATH` */
class EnvVarAccess extends VarAccess {
EnvVarAccess() { super.getVariable() instanceof EnvVariable }

override EnvVariable getVariable() { result = super.getVariable() }

string getEnvironmentVariable() { result = this.getVariable().getEnvironmentVariable() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,11 @@ module StmtNodes {
final override string getName() { result = s.getCmdName().getValue().getValue() }
}

/** A control-flow node that wraps a call to operator `&` */
class CallOperatorCfgNode extends CmdCfgNode {
CallOperatorCfgNode() { this.getStmt() instanceof CallOperator }
}

private class AssignStmtChildMapping extends PipelineBaseChildMapping, AssignStmt {
override predicate relevantChild(Ast n) {
n = this.getLeftHandSide() or n = this.getRightHandSide()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** Provides classes representing various flow sources for taint tracking. */
import semmle.code.powershell.dataflow.internal.DataFlowPublic as DataFlow
private import semmle.code.powershell.dataflow.internal.DataFlowPublic as DataFlow
import semmle.code.powershell.dataflow.flowsources.Remote
import semmle.code.powershell.dataflow.flowsources.Local
import semmle.code.powershell.frameworks.data.internal.ApiGraphModels
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ abstract class EnvironmentVariableSource extends LocalFlowSource {
override string getSourceType() { result = "environment variable" }
}

private class EnvironmentVariableEnv extends EnvironmentVariableSource {
EnvironmentVariableEnv() {
this.asExpr().getExpr().(VarReadAccess).getVariable() instanceof EnvVariable
}
}

private class ExternalEnvironmentVariableSource extends EnvironmentVariableSource {
ExternalEnvironmentVariableSource() {
this = ModelOutput::getASourceNode("environment", _).asSource()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,30 @@ class CallNode extends AstNode {

Node getQualifier() { result.asExpr() = call.getQualifier() }

/** Gets the i'th argument to this call. */
Node getArgument(int i) { result.asExpr() = call.getArgument(i) }

/** Gets the i'th positional argument to this call. */
Node getPositionalArgument(int i) { result.asExpr() = call.getPositionalArgument(i) }

/** Gets the argument with the name `name`, if any. */
Node getNamedArgument(string name) { result.asExpr() = call.getNamedArgument(name) }

/**
* Gets any argument of this call.
*
* Note that this predicate doesn't get the pipeline argument, if any.
*/
Node getAnArgument() { result.asExpr() = call.getAnArgument() }

int getNumberOfArguments() { result = call.getNumberOfArguments() }
}

/** A call to operator `&`, viwed as a node in a data flow graph. */
class CallOperatorNode extends CallNode {
CallOperatorNode() { this.getCallNode() instanceof CfgNodes::StmtNodes::CallOperatorCfgNode }
}

/** A use of a type name, viewed as a node in a data flow graph. */
class TypeNameNode extends ExprNode {
override CfgNodes::ExprNodes::TypeNameCfgNode n;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,15 @@ private module Cached {
}

import Cached
import SpeculativeTaintFlow

private module SpeculativeTaintFlow {
private import semmle.code.powershell.dataflow.internal.DataFlowDispatch as DataFlowDispatch
private import semmle.code.powershell.dataflow.internal.DataFlowPublic as DataFlowPublic

/**
* Holds if the additional step from `src` to `sink` should be considered in
* speculative taint flow exploration.
*/
predicate speculativeTaintStep(DataFlow::Node src, DataFlow::Node sink) { none() }
}