Support RunExpr's env vars

This commit is contained in:
Alvaro Muñoz
2024-02-08 11:56:22 +01:00
parent 1708e0f19d
commit 83ca36bc76
4 changed files with 65 additions and 4 deletions

View File

@@ -169,6 +169,13 @@ class RunExpr extends StepStmt, Expression {
Expression getScriptExpr() { result = scriptExpr }
Expression getEnvExpr(string name) {
exists(Actions::StepEnv env |
env.getStep() = this and
env.(YamlMapping).maps(any(YamlScalar s | s.getValue() = name), result)
)
}
string getScript() { result = scriptExpr.getValue() }
}
@@ -183,6 +190,7 @@ class ExprAccessExpr extends Expression instanceof YamlString {
string getExpression() { result = expr }
JobStmt getJob() { result.getAChildNode*() = this }
//override string toString() { result = expr }
}
/**

View File

@@ -171,8 +171,18 @@ private class UsesTree extends StandardPreOrderTree instanceof UsesExpr {
}
private class RunTree extends StandardPreOrderTree instanceof RunExpr {
override ControlFlowTree getChildNode(int i) { result = super.getScriptExpr() and i = 0 }
//override ControlFlowTree getChildNode(int i) { result = super.getScriptExpr() and i = 0 }
override ControlFlowTree getChildNode(int i) {
result =
rank[i](Expression child, Location l |
(child = super.getEnvExpr(_) or child = super.getScriptExpr()) and
l = child.getLocation()
|
child
order by
l.getStartLine(), l.getStartColumn(), l.getEndColumn(), l.getEndLine(), child.toString()
)
}
}
private class ExprAccessTree extends LeafTree instanceof ExprAccessExpr { }

View File

@@ -20,6 +20,9 @@ class AdditionalTaintStep extends Unit {
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
}
/**
* Holds if actions-find-and-replace-string step is used.
*/
private class ActionsFindAndReplaceStringStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(UsesExpr u |
@@ -29,3 +32,32 @@ private class ActionsFindAndReplaceStringStep extends AdditionalTaintStep {
)
}
}
/**
* Holds if a Run step declares an environment variable, uses it in its script and sets an output in its script.
* e.g.
* - name: Extract and Clean Initial URL
* id: extract-url
* env:
* BODY: ${{ github.event.comment.body }}
* run: |
* INITIAL_URL=$(echo "$BODY" | grep -o 'https://github.com/github/release-assets/assets/[^ >]*')
* echo "Cleaned Initial URL: $INITIAL_URL"
* echo "::set-output name=initial_url::$INITIAL_URL"
*/
private class RunEnvToScriptStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { test(pred, succ) }
}
predicate test(DataFlow::Node pred, DataFlow::Node succ) {
exists(RunExpr r, string varName |
r.getEnvExpr(varName) = pred.asExpr() and
exists(string script, string line |
script = r.getScript() and
line = script.splitAt("\n") and
line.regexpMatch(".*::set-output\\s+name.*") and
script.indexOf("$" + ["", "{", "ENV{"] + varName) > 0
) and
succ.asExpr() = r
)
}

View File

@@ -197,7 +197,7 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos =
*/
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { localFlowStep(nodeFrom, nodeTo) }
predicate stepOutputDefToUse(Node nodeFrom, Node nodeTo) {
predicate usesOutputDefToUse(Node nodeFrom, Node nodeTo) {
// nodeTo is an OutputVarAccessExpr scoped with the namespace of the nodeFrom Step output
exists(UsesExpr uses, StepOutputAccessExpr outputRead |
uses = nodeFrom.asExpr() and
@@ -207,6 +207,16 @@ predicate stepOutputDefToUse(Node nodeFrom, Node nodeTo) {
)
}
predicate runOutputDefToUse(Node nodeFrom, Node nodeTo) {
// nodeTo is an OutputVarAccessExpr scoped with the namespace of the nodeFrom Step output
exists(RunExpr uses, StepOutputAccessExpr outputRead |
uses = nodeFrom.asExpr() and
outputRead = nodeTo.asExpr() and
outputRead.getStepId() = uses.getId() and
uses.getJob() = outputRead.getJob()
)
}
predicate jobOutputDefToUse(Node nodeFrom, Node nodeTo) {
// nodeTo is a JobOutputAccessExpr and nodeFrom is the Job output expression
exists(Expression astFrom, JobOutputAccessExpr astTo |
@@ -223,7 +233,8 @@ predicate jobOutputDefToUse(Node nodeFrom, Node nodeTo) {
*/
pragma[nomagic]
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
stepOutputDefToUse(nodeFrom, nodeTo) or
usesOutputDefToUse(nodeFrom, nodeTo) or
runOutputDefToUse(nodeFrom, nodeTo) or
jobOutputDefToUse(nodeFrom, nodeTo)
}