Skip to content

Commit 8997f2c

Browse files
authored
Merge pull request github#16697 from egregius313/egregius313/go/dataflow/threat-modeling
Go: Introduce Threat Modeling
2 parents 59a77a8 + b4ecc81 commit 8997f2c

26 files changed

+395
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added the `ThreatModelFlowSource` class to `FlowSources.qll`. The `ThreatModelFlowSource` class can be used to include sources which match the current *threat model* configuration. This is the first step in supporting threat modeling for Go.

go/ql/lib/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ upgrades: upgrades
88
dependencies:
99
codeql/dataflow: ${workspace}
1010
codeql/mad: ${workspace}
11+
codeql/threat-models: ${workspace}
1112
codeql/tutorial: ${workspace}
1213
codeql/util: ${workspace}
1314
dataExtensions:

go/ql/lib/semmle/go/security/FlowSources.qll

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import go
66
private import semmle.go.dataflow.ExternalFlow as ExternalFlow
7+
private import codeql.threatmodels.ThreatModels
78

89
/**
910
* DEPRECATED: Use `RemoteFlowSource` instead.
@@ -31,7 +32,9 @@ module RemoteFlowSource {
3132
* Extend this class to model new APIs. If you want to refine existing API models,
3233
* extend `RemoteFlowSource` instead.
3334
*/
34-
abstract class Range extends DataFlow::Node { }
35+
abstract class Range extends SourceNode {
36+
override string getThreatModel() { result = "remote" }
37+
}
3538

3639
/**
3740
* A source of data that is controlled by an untrusted user.
@@ -40,3 +43,27 @@ module RemoteFlowSource {
4043
MaDRemoteSource() { ExternalFlow::sourceNode(this, "remote") }
4144
}
4245
}
46+
47+
/**
48+
* A data flow source.
49+
*/
50+
abstract class SourceNode extends DataFlow::Node {
51+
/**
52+
* Gets a string that represents the source kind with respect to threat modeling.
53+
*/
54+
abstract string getThreatModel();
55+
}
56+
57+
/**
58+
* A class of data flow sources that respects the
59+
* current threat model configuration.
60+
*/
61+
class ThreatModelFlowSource extends DataFlow::Node {
62+
ThreatModelFlowSource() {
63+
exists(string kind |
64+
// Specific threat model.
65+
currentThreatModel(kind) and
66+
(this.(SourceNode).getThreatModel() = kind or ExternalFlow::sourceNode(this, kind))
67+
)
68+
}
69+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
private import go
2+
private import semmle.go.security.FlowSources
3+
private import semmle.go.dataflow.ExternalFlow
4+
private import semmle.go.dataflow.DataFlow
5+
6+
private module ThreatModelConfig implements DataFlow::ConfigSig {
7+
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
8+
9+
predicate isSink(DataFlow::Node sink) {
10+
sink = any(DataFlow::CallNode c | c.getTarget().getName() = "sink").getAnArgument()
11+
}
12+
}
13+
14+
module ThreatModelFlow = TaintTracking::Global<ThreatModelConfig>;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module semmle.go.dataflow.ThreatModels
2+
3+
go 1.22.3
4+
5+
require github.com/nonexistent/sources v0.0.0-20240601000000-0000000000000
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package main
2+
3+
import (
4+
"github.com/nonexistent/sources"
5+
"net/http"
6+
)
7+
8+
func Environment() {
9+
home := sources.ReadEnvironment("HOME")
10+
11+
sink("SELECT * FROM " + home)
12+
}
13+
14+
func Cli() {
15+
arg := sources.GetCliArg("arg")
16+
17+
sink("SELECT * FROM " + arg)
18+
}
19+
20+
func Custom() {
21+
query := sources.GetCustom("query")
22+
23+
sink("SELECT * FROM " + query)
24+
}
25+
26+
func StoredSqlInjection() {
27+
query := sources.ExecuteQuery("SELECT * FROM queries LIMIT 1")
28+
sink(query)
29+
}
30+
31+
func Handler(w http.ResponseWriter, r *http.Request) {
32+
query := r.URL.Query().Get("query")
33+
34+
sink("SELECT * FROM " + query)
35+
}
36+
37+
func sink(s string) {
38+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
edges
2+
| test.go:32:11:32:15 | selection of URL | test.go:32:11:32:23 | call to Query | provenance | MaD:738 |
3+
| test.go:32:11:32:23 | call to Query | test.go:32:11:32:36 | call to Get | provenance | MaD:745 |
4+
| test.go:32:11:32:36 | call to Get | test.go:34:7:34:30 | ...+... | provenance | |
5+
nodes
6+
| test.go:32:11:32:15 | selection of URL | semmle.label | selection of URL |
7+
| test.go:32:11:32:23 | call to Query | semmle.label | call to Query |
8+
| test.go:32:11:32:36 | call to Get | semmle.label | call to Get |
9+
| test.go:34:7:34:30 | ...+... | semmle.label | ...+... |
10+
subpaths
11+
#select
12+
| test.go:32:11:32:15 | selection of URL | test.go:34:7:34:30 | ...+... |
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
extensions:
2+
3+
- addsTo:
4+
pack: codeql/threat-models
5+
extensible: threatModelConfiguration
6+
data: []
7+
8+
- addsTo:
9+
pack: codeql/go-all
10+
extensible: sourceModel
11+
data:
12+
- ["github.com/nonexistent/sources", "", False, "ExecuteQuery", "", "", "ReturnValue", "database", "manual"]
13+
- ["github.com/nonexistent/sources", "", False, "ReadEnvironment", "", "", "ReturnValue", "environment", "manual"]
14+
- ["github.com/nonexistent/sources", "", False, "GetCustom", "", "", "ReturnValue", "custom", "manual"]
15+
- ["github.com/nonexistent/sources", "", False, "GetCliArg", "", "", "ReturnValue", "commandargs", "manual"]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* This is a dataflow test using the "default" threat model.
3+
*/
4+
5+
import Test
6+
import ThreatModelFlow::PathGraph
7+
8+
from ThreatModelFlow::PathNode source, ThreatModelFlow::PathNode sink
9+
where ThreatModelFlow::flowPath(source, sink)
10+
select source, sink
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
edges
2+
| test.go:27:11:27:63 | call to ExecuteQuery | test.go:28:7:28:11 | query | provenance | Src:MaD:1 |
3+
| test.go:32:11:32:15 | selection of URL | test.go:32:11:32:23 | call to Query | provenance | MaD:738 |
4+
| test.go:32:11:32:23 | call to Query | test.go:32:11:32:36 | call to Get | provenance | MaD:745 |
5+
| test.go:32:11:32:36 | call to Get | test.go:34:7:34:30 | ...+... | provenance | |
6+
nodes
7+
| test.go:27:11:27:63 | call to ExecuteQuery | semmle.label | call to ExecuteQuery |
8+
| test.go:28:7:28:11 | query | semmle.label | query |
9+
| test.go:32:11:32:15 | selection of URL | semmle.label | selection of URL |
10+
| test.go:32:11:32:23 | call to Query | semmle.label | call to Query |
11+
| test.go:32:11:32:36 | call to Get | semmle.label | call to Get |
12+
| test.go:34:7:34:30 | ...+... | semmle.label | ...+... |
13+
subpaths
14+
#select
15+
| test.go:27:11:27:63 | call to ExecuteQuery | test.go:28:7:28:11 | query |
16+
| test.go:32:11:32:15 | selection of URL | test.go:34:7:34:30 | ...+... |

0 commit comments

Comments
 (0)