Skip to content

Commit 494fb24

Browse files
author
Alvaro Muñoz
committed
fix: refactor local, read and store steps
1 parent ebaac5f commit 494fb24

File tree

2 files changed

+22
-54
lines changed

2 files changed

+22
-54
lines changed

ql/lib/codeql/actions/dataflow/FlowSteps.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class AdditionalTaintStep extends Unit {
4040
* echo "foo=$(echo $TAINTED)" >> $GITHUB_OUTPUT
4141
* echo "test=${{steps.step1.outputs.MSG}}" >> "$GITHUB_OUTPUT"
4242
*/
43-
predicate runEnvToScriptstep(DataFlow::Node pred, DataFlow::Node succ, DataFlow::ContentSet c) {
43+
predicate runEnvToScriptStoreStep(DataFlow::Node pred, DataFlow::Node succ, DataFlow::ContentSet c) {
4444
exists(RunExpr r, string varName, string output |
4545
c = any(DataFlow::FieldContent ct | ct.getName() = output.replaceAll("output\\.", "")) and
4646
r.getEnvExpr(varName) = pred.asExpr() and

ql/lib/codeql/actions/dataflow/internal/DataFlowPrivate.qll

Lines changed: 21 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,9 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
133133

134134
newtype TContent =
135135
TFieldContent(string name) {
136+
// We only use field flow for steps and jobs outputs, not for accessing other context fields such as jobs, env or inputs
136137
name = any(StepsCtxAccessExpr a).getFieldName() or
137-
name = any(NeedsCtxAccessExpr a).getFieldName() or
138-
name = any(JobsCtxAccessExpr a).getFieldName()
138+
name = any(NeedsCtxAccessExpr a).getFieldName()
139139
}
140140

141141
/**
@@ -188,11 +188,12 @@ class ArgumentPosition extends string {
188188
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
189189

190190
/**
191-
* Holds if there is a local flow step between a ${{}} expression accesing a step output variable and the step output itself
192-
* But only for those cases where the step output is defined externally in a MaD specification.
193-
* The reason for this is that we don't currently have a way to specify that a source starts with a non-empty access
194-
* path so the easiest thing is to add the corresponding read steps of that field as local flow steps as well.
195-
* e.g. ${{ steps.step1.output.foo }}
191+
* Holds if there is a local flow step between a ${{ steps.xxx.outputs.yyy }} expression accesing a step output field
192+
* and the step output itself. But only for those cases where the step output is defined externally in a MaD Source
193+
* specification. The reason for this is that we don't currently have a way to specify that a source starts with a
194+
* non-empty access path so we cannot write a Source that stores the taint in a Content, we can only do that for steps
195+
* (storeStep). The easiest thing is to add this local flow step that simulates a read step from the source node for a specific
196+
* field name.
196197
*/
197198
predicate stepsCtxLocalStep(Node nodeFrom, Node nodeTo) {
198199
exists(StepStmt astFrom, StepsCtxAccessExpr astTo |
@@ -204,19 +205,6 @@ predicate stepsCtxLocalStep(Node nodeFrom, Node nodeTo) {
204205
)
205206
}
206207

207-
/**
208-
* Holds if there is a local flow step between a ${{}} expression accesing a job output variable and the job output itself
209-
* e.g. ${{ needs.job1.output.foo }} or ${{ jobs.job1.output.foo }}
210-
*/
211-
predicate jobsCtxLocalStep(Node nodeFrom, Node nodeTo) {
212-
exists(Expression astFrom, CtxAccessExpr astTo |
213-
astFrom = nodeFrom.asExpr() and
214-
astTo = nodeTo.asExpr() and
215-
astTo.getRefExpr() = astFrom and
216-
(astTo instanceof NeedsCtxAccessExpr or astTo instanceof JobsCtxAccessExpr)
217-
)
218-
}
219-
220208
/**
221209
* Holds if there is a local flow step between a ${{}} expression accesing an input variable and the input itself
222210
* e.g. ${{ inputs.foo }}
@@ -252,7 +240,6 @@ predicate envCtxLocalStep(Node nodeFrom, Node nodeTo) {
252240
pragma[nomagic]
253241
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
254242
stepsCtxLocalStep(nodeFrom, nodeTo) or
255-
jobsCtxLocalStep(nodeFrom, nodeTo) or
256243
inputsCtxLocalStep(nodeFrom, nodeTo) or
257244
envCtxLocalStep(nodeFrom, nodeTo)
258245
}
@@ -272,17 +259,12 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { localFlowStep(nodeFr
272259
*/
273260
predicate jumpStep(Node nodeFrom, Node nodeTo) { none() }
274261

275-
/**
276-
* A read step to read the value of a ReusableWork uses step and connect it to its
277-
* corresponding JobOutputAccessExpr
278-
*/
279-
predicate reusableWorkflowReturnReadStep(Node node1, Node node2, ContentSet c) {
280-
exists(NeedsCtxAccessExpr expr, string fieldName |
281-
expr.usesReusableWorkflow() and
282-
expr.getRefExpr() = node1.asExpr() and
283-
expr.getFieldName() = fieldName and
284-
expr = node2.asExpr() and
285-
c = any(FieldContent ct | ct.getName() = fieldName)
262+
predicate ctxFieldReadStep(Node node1, Node node2, ContentSet c) {
263+
exists(CtxAccessExpr access |
264+
(access instanceof NeedsCtxAccessExpr or access instanceof StepsCtxAccessExpr) and
265+
c = any(FieldContent ct | ct.getName() = access.getFieldName()) and
266+
node1.asExpr() = access.getRefExpr() and
267+
node2.asExpr() = access
286268
)
287269
}
288270

@@ -291,24 +273,14 @@ predicate reusableWorkflowReturnReadStep(Node node1, Node node2, ContentSet c) {
291273
* `node1` references an object with a content `c.getAReadContent()` whose
292274
* value ends up in `node2`.
293275
*/
294-
predicate readStep(Node node1, ContentSet c, Node node2) {
295-
// TODO: Extract to its own predicate
296-
exists(StepsCtxAccessExpr access |
297-
c = any(FieldContent ct | ct.getName() = access.getFieldName()) and
298-
node1.asExpr() = access.getRefExpr() and
299-
node2.asExpr() = access
300-
)
301-
or
302-
reusableWorkflowReturnReadStep(node1, node2, c)
303-
}
276+
predicate readStep(Node node1, ContentSet c, Node node2) { ctxFieldReadStep(node1, node2, c) }
304277

305278
/**
306-
* A store step to store the value of a ReusableWorkflowStmt output expr into the return node (node2)
279+
* A store step to store an output expression (node1) into its OutputsStm node (node2)
307280
* with a given access path (fieldName)
308281
*/
309-
predicate reusableWorkflowReturnStoreStep(Node node1, Node node2, ContentSet c) {
310-
exists(ReusableWorkflowStmt stmt, OutputsStmt out, string fieldName |
311-
out = stmt.getOutputsStmt() and
282+
predicate fieldStoreStep(Node node1, Node node2, ContentSet c) {
283+
exists(OutputsStmt out, string fieldName |
312284
node1.asExpr() = out.getOutputExpr(fieldName) and
313285
node2.asExpr() = out and
314286
c = any(FieldContent ct | ct.getName() = fieldName)
@@ -321,13 +293,9 @@ predicate reusableWorkflowReturnStoreStep(Node node1, Node node2, ContentSet c)
321293
* contains the value of `node1`.
322294
*/
323295
predicate storeStep(Node node1, ContentSet c, Node node2) {
324-
reusableWorkflowReturnStoreStep(node1, node2, c)
325-
or
326-
// TODO: rename to xxxxStoreStep
327-
externallyDefinedSummary(node1, node2, c)
328-
or
329-
// TODO: rename to xxxxStoreStep
330-
runEnvToScriptstep(node1, node2, c)
296+
fieldStoreStep(node1, node2, c) or
297+
externallyDefinedStoreStep(node1, node2, c) or
298+
runEnvToScriptStoreStep(node1, node2, c)
331299
}
332300

333301
/**

0 commit comments

Comments
 (0)