Merge pull request #7 from GitHubSecurityLab/input_output_nodes

Better handling of input and output expressions
This commit is contained in:
Alvaro Muñoz
2024-02-13 11:52:10 +01:00
committed by GitHub
5 changed files with 37 additions and 35 deletions

View File

@@ -92,15 +92,23 @@ class OutputsStmt extends Statement instanceof YamlMapping {
* Gets a specific output expression (YamlMapping) by name.
*/
OutputExpr getOutputExpr(string name) {
this.(YamlMapping).lookup(name).(YamlMapping).lookup("value") = result
this.(YamlMapping).lookup(name).(YamlMapping).lookup("value") = result or
this.(YamlMapping).lookup(name) = result
}
}
// TODO: Needs a characteristic predicate otherwise anything is an output expression
class InputExpr extends Expression instanceof YamlString { }
class InputExpr extends Expression instanceof YamlString {
InputExpr() { exists(InputsStmt inputs | inputs.(YamlMapping).maps(this, _)) }
}
// TODO: Needs a characteristic predicate otherwise anything is an output expression
class OutputExpr extends Expression instanceof YamlString { }
class OutputExpr extends Expression instanceof YamlString {
OutputExpr() {
exists(OutputsStmt outputs |
outputs.(YamlMapping).lookup(_).(YamlMapping).lookup("value") = this or
outputs.(YamlMapping).lookup(_) = this
)
}
}
/**
* A Job is a collection of steps that run in an execution environment.

View File

@@ -35,11 +35,7 @@ module Completion {
override string toString() { result = "BooleanCompletion(" + value + ")" }
override predicate isValidForSpecific(AstNode e) {
none()
// TODO: add support for conditional expressions?
//e = any(ConditionalExpression c).getCondition()
}
override predicate isValidForSpecific(AstNode e) { none() }
override BooleanSuccessor getAMatchingSuccessorType() { result.getValue() = value }

View File

@@ -48,22 +48,22 @@ class ExprNode extends Node, TExprNode {
* Reusable workflow input nodes
*/
class ParameterNode extends ExprNode {
private InputExpr parameter;
private InputExpr input;
ParameterNode() {
this.asExpr() = parameter and
parameter = any(ReusableWorkflowStmt w).getInputsStmt().getInputExpr(_)
this.asExpr() = input and
input = any(InputsStmt s).getInputExpr(_)
}
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
parameter = c.(ReusableWorkflowStmt).getInputsStmt().getInputExpr(pos)
input = c.(ReusableWorkflowStmt).getInputsStmt().getInputExpr(pos)
}
override string toString() { result = parameter.toString() }
override string toString() { result = "input " + input.toString() }
override Location getLocation() { result = parameter.getLocation() }
override Location getLocation() { result = input.getLocation() }
InputExpr getInputExpr() { result = parameter }
InputExpr getInputExpr() { result = input }
}
/**
@@ -83,19 +83,18 @@ class ArgumentNode extends ExprNode {
* Reusable workflow output nodes
*/
class ReturnNode extends ExprNode {
private Cfg::Node node;
private OutputExpr output;
ReturnNode() {
this.getCfgNode() = node and
(node.getAstNode() = any(ReusableWorkflowStmt w).getOutputsStmt().getOutputExpr(_) or
node.getAstNode() = any(CompositeActionStmt a).getOutputsStmt().getOutputExpr(_))
this.asExpr() = output and
output = any(OutputsStmt s).getOutputExpr(_)
}
ReturnKind getKind() { result = TNormalReturn() }
override string toString() { result = "return " + node.toString() }
override string toString() { result = "output " + output.toString() }
override Location getLocation() { result = node.getLocation() }
override Location getLocation() { result = output.getLocation() }
}
/** Gets the node corresponding to `e`. */

View File

@@ -15,16 +15,16 @@ import codeql.actions.TaintTracking
import codeql.actions.dataflow.FlowSources
import codeql.actions.dataflow.ExternalFlow
private class OutputVariableSink extends DataFlow::Node {
OutputVariableSink() { exists(OutputsStmt s | s.getOutputExpr(_) = this.asExpr()) }
}
private module MyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof DataFlow::ParameterNode and
exists(CompositeActionStmt c | c.getInputsStmt().getInputExpr(_) = source.asExpr())
}
predicate isSink(DataFlow::Node sink) { sink instanceof OutputVariableSink }
predicate isSink(DataFlow::Node sink) {
sink instanceof DataFlow::ReturnNode and
exists(CompositeActionStmt c | c.getOutputsStmt().getOutputExpr(_) = sink.asExpr())
}
}
module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -15,18 +15,17 @@ import codeql.actions.TaintTracking
import codeql.actions.dataflow.FlowSources
import codeql.actions.dataflow.ExternalFlow
private class OutputVariableSink extends DataFlow::Node {
OutputVariableSink() { exists(OutputsStmt s | s.getOutputExpr(_) = this.asExpr()) }
}
private module MyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource and
exists(CompositeActionStmt c | c.getAChildNode*() = source.asExpr()) and
not exists(CompositeActionStmt c | c.getInputsStmt().getInputExpr(_) = source.asExpr())
not source instanceof DataFlow::ParameterNode and
exists(CompositeActionStmt c | c.getAChildNode*() = source.asExpr())
}
predicate isSink(DataFlow::Node sink) { sink instanceof OutputVariableSink }
predicate isSink(DataFlow::Node sink) {
sink instanceof DataFlow::ReturnNode and
exists(CompositeActionStmt c | c.getOutputsStmt().getOutputExpr(_) = sink.asExpr())
}
}
module MyFlow = TaintTracking::Global<MyConfig>;