Skip to content

Commit f2fc411

Browse files
author
Alvaro Muñoz
authored
Merge pull request #3 from GitHubSecurityLab/extensible_predicates
Add support for external definitions
2 parents e9c1114 + 2eaca7e commit f2fc411

File tree

10 files changed

+150
-24
lines changed

10 files changed

+150
-24
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
private import internal.ExternalFlowExtensions as Extensions
2+
import codeql.actions.DataFlow
3+
import actions
4+
5+
/** Holds if a source model exists for the given parameters. */
6+
predicate sourceModel(string action, string version, string output, string kind) {
7+
Extensions::sourceModel(action, version, output, kind)
8+
}
9+
10+
/** Holds if a sink model exists for the given parameters. */
11+
predicate summaryModel(string action, string version, string input, string output, string kind) {
12+
Extensions::summaryModel(action, version, input, output, kind)
13+
}
14+
15+
/** Holds if a sink model exists for the given parameters. */
16+
predicate sinkModel(string action, string version, string input, string kind) {
17+
Extensions::sinkModel(action, version, input, kind)
18+
}
19+
20+
predicate sinkNode(DataFlow::ExprNode sink, string kind) {
21+
exists(UsesExpr uses, string action, string version, string input |
22+
uses.getArgumentExpr(input.splitAt(",").trim()) = sink.asExpr() and
23+
sinkModel(action, version, input, kind) and
24+
uses.getCallee() = action and
25+
(
26+
if version.trim() = "*"
27+
then uses.getVersion() = any(string v)
28+
else uses.getVersion() = version.splitAt(",").trim()
29+
)
30+
)
31+
}

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import actions
22
import codeql.actions.DataFlow
3+
import codeql.actions.dataflow.ExternalFlow
34

45
/**
56
* A data flow source.
@@ -124,14 +125,22 @@ private class EventSource extends RemoteFlowSource {
124125
override string getSourceType() { result = "User-controlled events" }
125126
}
126127

127-
private class ChangedFilesSource extends RemoteFlowSource {
128-
ChangedFilesSource() {
129-
exists(UsesExpr uses |
130-
uses.getCallee() = "tj-actions/changed-files" and
131-
uses.getVersion() = ["v10", "v20", "v30", "v40"] and
132-
uses = this.asExpr()
128+
private class ExternallyDefinedSource extends RemoteFlowSource {
129+
string soutceType;
130+
131+
ExternallyDefinedSource() {
132+
exists(UsesExpr uses, string action, string version, /*string output,*/ string kind |
133+
sourceModel(action, version, _, kind) and
134+
uses.getCallee() = action and
135+
(
136+
if version.trim() = "*"
137+
then uses.getVersion() = any(string v)
138+
else uses.getVersion() = version.splitAt(",").trim()
139+
) and
140+
uses = this.asExpr() and
141+
soutceType = kind
133142
)
134143
}
135144

136-
override string getSourceType() { result = "User-controlled list of changed files" }
145+
override string getSourceType() { result = soutceType }
137146
}

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

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import actions
66
private import codeql.util.Unit
77
private import codeql.actions.DataFlow
8+
import codeql.actions.dataflow.ExternalFlow
89

910
/**
1011
* A unit class for adding additional taint steps.
@@ -20,16 +21,23 @@ class AdditionalTaintStep extends Unit {
2021
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
2122
}
2223

23-
/**
24-
* Holds if actions-find-and-replace-string step is used.
25-
*/
26-
private class ActionsFindAndReplaceStringStep extends AdditionalTaintStep {
24+
predicate externallyDefinedSummary(DataFlow::Node pred, DataFlow::Node succ) {
25+
exists(UsesExpr uses, string action, string version, string input |
26+
/*, string output */ summaryModel(action, version, input, _, "taint") and
27+
uses.getCallee() = action and
28+
(
29+
if version.trim() = "*"
30+
then uses.getVersion() = any(string v)
31+
else uses.getVersion() = version.splitAt(",").trim()
32+
) and
33+
pred.asExpr() = uses.getArgumentExpr(input.splitAt(",").trim()) and
34+
succ.asExpr() = uses
35+
)
36+
}
37+
38+
private class ExternallyDefinedSummary extends AdditionalTaintStep {
2739
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
28-
exists(UsesExpr u |
29-
u.getCallee() = "mad9000/actions-find-and-replace-string" and
30-
pred.asExpr() = u.getArgumentExpr(["source", "replace"]) and
31-
succ.asExpr() = u
32-
)
40+
externallyDefinedSummary(pred, succ)
3341
}
3442
}
3543

@@ -46,10 +54,12 @@ private class ActionsFindAndReplaceStringStep extends AdditionalTaintStep {
4654
* echo "::set-output name=initial_url::$INITIAL_URL"
4755
*/
4856
private class RunEnvToScriptStep extends AdditionalTaintStep {
49-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { test(pred, succ) }
57+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
58+
runEnvToScriptstep(pred, succ)
59+
}
5060
}
5161

52-
predicate test(DataFlow::Node pred, DataFlow::Node succ) {
62+
predicate runEnvToScriptstep(DataFlow::Node pred, DataFlow::Node succ) {
5363
exists(RunExpr r, string varName |
5464
r.getEnvExpr(varName) = pred.asExpr() and
5565
exists(string script, string line |
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* This module provides extensible predicates for defining MaD models.
3+
*/
4+
5+
/**
6+
* Holds if a source model exists for the given parameters.
7+
*/
8+
extensible predicate sourceModel(string action, string version, string output, string kind);
9+
10+
/**
11+
* Holds if a summary model exists for the given parameters.
12+
*/
13+
extensible predicate summaryModel(
14+
string action, string version, string input, string output, string kind
15+
);
16+
17+
/**
18+
* Holds if a sink model exists for the given parameters.
19+
*/
20+
extensible predicate sinkModel(string action, string version, string input, string kind);

ql/lib/ext/sinks.model.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/actions-all
4+
extensible: sinkModel
5+
data:
6+
- [
7+
"FAKE-mad9000/actions-find-and-replace-string",
8+
"*",
9+
"source",
10+
"expression-injection",
11+
]

ql/lib/ext/sources.model.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/actions-all
4+
extensible: sourceModel
5+
data:
6+
- [
7+
"tj-actions/changed-files",
8+
"v10, v20, v30, v40",
9+
"all_changed_file",
10+
"PR",
11+
]

ql/lib/ext/summaries.model.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/actions-all
4+
extensible: summaryModel
5+
data:
6+
- [
7+
"mad9000/actions-find-and-replace-string",
8+
"*",
9+
"source, replace",
10+
"value",
11+
"taint",
12+
]
13+
- [
14+
"frabert/replace-string-action",
15+
"*",
16+
"string, replace-with",
17+
"replaced",
18+
"taint",
19+
]

ql/lib/qlpack.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ name: codeql/actions-all
55
version: 0.0.1-dev
66
dependencies:
77
codeql/controlflow: ^0.1.7
8-
codeql/yaml: '*'
9-
codeql/util: '*'
8+
codeql/yaml: "*"
9+
codeql/util: "*"
1010
codeql/dataflow: ^0.1.7
1111
dbscheme: yaml.dbscheme
1212
extractor: yaml
1313
tests: test
1414
groups:
15-
- yaml
15+
- yaml
16+
dataExtensions:
17+
- ext/*.model.yml

ql/lib/test/test.ql

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import codeql.actions.Ast
33
import codeql.actions.Cfg as Cfg
44
import codeql.actions.DataFlow
55
import codeql.Locations
6+
import codeql.actions.dataflow.ExternalFlow
67

78
query predicate files(File f) { any() }
89

@@ -19,7 +20,7 @@ query predicate stepUsesNodes(StepUsesExpr s) { any() }
1920
query predicate jobUsesNodes(JobUsesExpr s) { any() }
2021

2122
query predicate usesSteps(UsesExpr call, string argname, Expression arg) {
22-
call.getArgument(argname) = arg
23+
call.getArgumentExpr(argname) = arg
2324
}
2425

2526
query predicate runSteps1(RunExpr run, string body) { run.getScript() = body }
@@ -48,7 +49,7 @@ query predicate parentNodes(AstNode child, AstNode parent) { child.getParentNode
4849

4950
query predicate cfgNodes(Cfg::Node n) {
5051
//any()
51-
n.getAstNode() instanceof OutputsStmt
52+
n.getAstNode() instanceof ReusableWorkflowOutputsStmt
5253
}
5354

5455
query predicate dfNodes(DataFlow::Node e) {
@@ -68,3 +69,11 @@ query predicate varIds(StepOutputAccessExpr s, string a) { s.getStepId() = a }
6869
query predicate nodeLocations(DataFlow::Node n, Location l) { n.getLocation() = l }
6970

7071
query predicate scopes(Cfg::CfgScope c) { any() }
72+
73+
query predicate sources(string action, string version, string output, string kind) {
74+
sourceModel(action, version, output, kind)
75+
}
76+
77+
query predicate summaries(string action, string version, string input, string output, string kind) {
78+
summaryModel(action, version, input, output, kind)
79+
}

ql/src/Security/CWE-094/ExpressionInjection.ql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
import actions
1616
import codeql.actions.TaintTracking
1717
import codeql.actions.dataflow.FlowSources
18+
import codeql.actions.dataflow.ExternalFlow
1819

1920
private class ExpressionInjectionSink extends DataFlow::Node {
20-
ExpressionInjectionSink() { exists(RunExpr e | e.getScriptExpr() = this.asExpr()) }
21+
ExpressionInjectionSink() {
22+
exists(RunExpr e | e.getScriptExpr() = this.asExpr()) or
23+
sinkNode(this, "expression-injection")
24+
}
2125
}
2226

2327
private module MyConfig implements DataFlow::ConfigSig {

0 commit comments

Comments
 (0)