Skip to content

Commit d8ca8dd

Browse files
authored
Merge pull request #19203 from owen-mc/review/egregius313/17905
Go: Add database source models for `uptrace/bun` and `gogf/gf/database/gdb`
2 parents bf7d3d1 + 1ed8fbd commit d8ca8dd

File tree

15 files changed

+4438
-16
lines changed

15 files changed

+4438
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Local source models for APIs reading from databases have been added for `github.com/gogf/gf/database/gdb` and `github.com/uptrace/bun`.

go/ql/lib/ext/github.com.gogf.gf.database.gdb.model.yml

+73
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,76 @@ extensions:
5555
- ["github.com/gogf/gf/database/gdb", "Tx", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
5656
- ["github.com/gogf/gf/database/gdb", "Tx", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
5757
- ["github.com/gogf/gf/database/gdb", "Tx", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"]
58+
- addsTo:
59+
pack: codeql/go-all
60+
extensible: sourceModel
61+
data:
62+
# These models are for v1. Some of them hold for v2, but we should model v2 properly.
63+
- ["github.com/gogf/gf/database/gdb", "Core", True, "DoGetAll", "", "", "ReturnValue[0]", "database", "manual"]
64+
- ["github.com/gogf/gf/database/gdb", "Core", True, "DoQuery", "", "", "ReturnValue[0]", "database", "manual"]
65+
- ["github.com/gogf/gf/database/gdb", "Core", True, "GetAll", "", "", "ReturnValue[0]", "database", "manual"]
66+
- ["github.com/gogf/gf/database/gdb", "Core", True, "GetArray", "", "", "ReturnValue[0]", "database", "manual"]
67+
- ["github.com/gogf/gf/database/gdb", "Core", True, "GetOne", "", "", "ReturnValue[0]", "database", "manual"]
68+
- ["github.com/gogf/gf/database/gdb", "Core", True, "GetScan", "", "", "Argument[0]", "database", "manual"]
69+
- ["github.com/gogf/gf/database/gdb", "Core", True, "GetStruct", "", "", "Argument[0]", "database", "manual"]
70+
- ["github.com/gogf/gf/database/gdb", "Core", True, "GetStructs", "", "", "Argument[0]", "database", "manual"]
71+
- ["github.com/gogf/gf/database/gdb", "Core", True, "GetValue", "", "", "ReturnValue[0]", "database", "manual"]
72+
- ["github.com/gogf/gf/database/gdb", "Core", True, "Query", "", "", "ReturnValue[0]", "database", "manual"]
73+
74+
- ["github.com/gogf/gf/database/gdb", "DB", True, "DoGetAll", "", "", "ReturnValue[0]", "database", "manual"]
75+
- ["github.com/gogf/gf/database/gdb", "DB", True, "DoQuery", "", "", "ReturnValue[0]", "database", "manual"]
76+
- ["github.com/gogf/gf/database/gdb", "DB", True, "GetAll", "", "", "ReturnValue[0]", "database", "manual"]
77+
- ["github.com/gogf/gf/database/gdb", "DB", True, "GetArray", "", "", "ReturnValue[0]", "database", "manual"]
78+
- ["github.com/gogf/gf/database/gdb", "DB", True, "GetOne", "", "", "ReturnValue[0]", "database", "manual"]
79+
- ["github.com/gogf/gf/database/gdb", "DB", True, "GetScan", "", "", "Argument[0]", "database", "manual"]
80+
- ["github.com/gogf/gf/database/gdb", "DB", True, "GetValue", "", "", "ReturnValue[0]", "database", "manual"]
81+
- ["github.com/gogf/gf/database/gdb", "DB", True, "Query", "", "", "ReturnValue[0]", "database", "manual"]
82+
83+
- ["github.com/gogf/gf/database/gdb", "Model", True, "All", "", "", "ReturnValue[0]", "database", "manual"]
84+
- ["github.com/gogf/gf/database/gdb", "Model", True, "Array", "", "", "ReturnValue[0]", "database", "manual"]
85+
- ["github.com/gogf/gf/database/gdb", "Model", True, "FindAll", "", "", "ReturnValue[0]", "database", "manual"]
86+
- ["github.com/gogf/gf/database/gdb", "Model", True, "FindArray", "", "", "ReturnValue[0]", "database", "manual"]
87+
- ["github.com/gogf/gf/database/gdb", "Model", True, "FindOne", "", "", "ReturnValue[0]", "database", "manual"]
88+
- ["github.com/gogf/gf/database/gdb", "Model", True, "FindScan", "", "", "Argument[0]", "database", "manual"]
89+
- ["github.com/gogf/gf/database/gdb", "Model", True, "FindValue", "", "", "ReturnValue[0]", "database", "manual"]
90+
- ["github.com/gogf/gf/database/gdb", "Model", True, "One", "", "", "ReturnValue[0]", "database", "manual"]
91+
- ["github.com/gogf/gf/database/gdb", "Model", True, "Scan", "", "", "Argument[0]", "database", "manual"]
92+
- ["github.com/gogf/gf/database/gdb", "Model", True, "ScanList", "", "", "Argument[0]", "database", "manual"]
93+
- ["github.com/gogf/gf/database/gdb", "Model", True, "Select", "", "", "ReturnValue[0]", "database", "manual"]
94+
- ["github.com/gogf/gf/database/gdb", "Model", True, "Struct", "", "", "Argument[0]", "database", "manual"]
95+
- ["github.com/gogf/gf/database/gdb", "Model", True, "Structs", "", "", "Argument[0]", "database", "manual"]
96+
- ["github.com/gogf/gf/database/gdb", "Model", True, "Value", "", "", "ReturnValue[0]", "database", "manual"]
97+
98+
- ["github.com/gogf/gf/database/gdb", "TX", True, "GetAll", "", "", "ReturnValue[0]", "database", "manual"]
99+
- ["github.com/gogf/gf/database/gdb", "TX", True, "GetOne", "", "", "ReturnValue[0]", "database", "manual"]
100+
- ["github.com/gogf/gf/database/gdb", "TX", True, "GetScan", "", "", "Argument[0]", "database", "manual"]
101+
- ["github.com/gogf/gf/database/gdb", "TX", True, "GetStruct", "", "", "Argument[0]", "database", "manual"]
102+
- ["github.com/gogf/gf/database/gdb", "TX", True, "GetStructs", "", "", "Argument[0]", "database", "manual"]
103+
- ["github.com/gogf/gf/database/gdb", "TX", True, "GetValue", "", "", "ReturnValue[0]", "database", "manual"]
104+
- ["github.com/gogf/gf/database/gdb", "TX", True, "Query", "", "", "ReturnValue[0]", "database", "manual"]
105+
- addsTo:
106+
pack: codeql/go-all
107+
extensible: summaryModel
108+
data:
109+
- ["github.com/gogf/gf/database/gdb", "Record", True, "GMap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
110+
- ["github.com/gogf/gf/database/gdb", "Record", True, "Interface", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
111+
- ["github.com/gogf/gf/database/gdb", "Record", True, "Json", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
112+
- ["github.com/gogf/gf/database/gdb", "Record", True, "Map", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
113+
- ["github.com/gogf/gf/database/gdb", "Record", True, "Struct", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
114+
- ["github.com/gogf/gf/database/gdb", "Record", True, "Xml", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
115+
116+
- ["github.com/gogf/gf/database/gdb", "Result", True, "Array", "", "", "Argument[receiver]", "ReturnValue.ArrayElement", "taint", "manual"]
117+
- ["github.com/gogf/gf/database/gdb", "Result", True, "Chunk", "", "", "Argument[receiver]", "ReturnValue.ArrayElement", "taint", "manual"]
118+
- ["github.com/gogf/gf/database/gdb", "Result", True, "Interface", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
119+
- ["github.com/gogf/gf/database/gdb", "Result", True, "Json", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
120+
- ["github.com/gogf/gf/database/gdb", "Result", True, "List", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
121+
- ["github.com/gogf/gf/database/gdb", "Result", True, "MapKeyInt", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
122+
- ["github.com/gogf/gf/database/gdb", "Result", True, "MapKeyStr", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
123+
- ["github.com/gogf/gf/database/gdb", "Result", True, "MapKeyUint", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
124+
- ["github.com/gogf/gf/database/gdb", "Result", True, "MapKeyValue", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
125+
- ["github.com/gogf/gf/database/gdb", "Result", True, "RecordKeyInt", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
126+
- ["github.com/gogf/gf/database/gdb", "Result", True, "RecordKeyStr", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
127+
- ["github.com/gogf/gf/database/gdb", "Result", True, "RecordKeyUint", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
128+
- ["github.com/gogf/gf/database/gdb", "Result", True, "ScanList", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
129+
- ["github.com/gogf/gf/database/gdb", "Result", True, "Structs", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
130+
- ["github.com/gogf/gf/database/gdb", "Result", True, "Xml", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]

go/ql/lib/ext/github.com.uptrace.bun.model.yml

+23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
11
extensions:
2+
- addsTo:
3+
pack: codeql/go-all
4+
extensible: sourceModel
5+
data:
6+
- ["github.com/uptrace/bun", "DB", True, "Query", "", "", "ReturnValue[0]", "database", "manual"]
7+
- ["github.com/uptrace/bun", "DB", True, "QueryRow", "", "", "ReturnValue", "database", "manual"]
8+
- ["github.com/uptrace/bun", "IDB", True, "QueryContext", "", "", "ReturnValue[0]", "database", "manual"]
9+
- ["github.com/uptrace/bun", "IDB", True, "QueryRowContext", "", "", "ReturnValue", "database", "manual"]
10+
# - ["github.com/uptrace/bun", "RawQuery", True, "Exec", "", "", "Argument[0]", "database", "manual"] # Implemented in QL because variadic arguments as sources aren't supported in this format yet
11+
# - ["github.com/uptrace/bun", "RawQuery", True, "Scan", "", "", "Argument[0]", "database", "manual"] # Implemented in QL because variadic arguments as sources aren't supported in this format yet
12+
# - ["github.com/uptrace/bun", "SelectQuery", True, "Exec", "", "", "Argument[0]", "database", "manual"] # Implemented in QL because variadic arguments as sources aren't supported in this format yet
13+
- ["github.com/uptrace/bun", "SelectQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
14+
- ["github.com/uptrace/bun", "SelectQuery", True, "Rows", "", "", "ReturnValue[0]", "database", "manual"]
15+
# - ["github.com/uptrace/bun", "SelectQuery", True, "Scan", "", "", "Argument[1]", "database", "manual"] # Implemented in QL because variadic arguments as sources aren't supported in this format yet
16+
# - ["github.com/uptrace/bun", "SelectQuery", True, "ScanAndCount", "", "", "Argument[1]", "database", "manual"] # Implemented in QL because variadic arguments as sources aren't supported in this format yet
17+
- ["github.com/uptrace/bun", "Tx", True, "Query", "", "", "ReturnValue[0]", "database", "manual"]
18+
- ["github.com/uptrace/bun", "Tx", True, "QueryRow", "", "", "ReturnValue", "database", "manual"]
219
- addsTo:
320
pack: codeql/go-all
421
extensible: sinkModel
@@ -66,3 +83,9 @@ extensions:
6683
- ["github.com/uptrace/bun", "UpdateQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
6784
- ["github.com/uptrace/bun", "UpdateQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
6885
- ["github.com/uptrace/bun", "UpdateQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"]
86+
# - addsTo:
87+
# pack: codeql/go-all
88+
# extensible: summaryModel
89+
# data:
90+
# - ["github.com/uptrace/bun", "DB", True, "ScanRow", "", "", "Argument[1]", "Argument[2].ArrayElement", "taint", "manual"] # Implemented in QL because variadic arguments as outputs aren't supported in this format yet
91+
# - ["github.com/uptrace/bun", "DB", True, "ScanRows", "", "", "Argument[1]", "Argument[2].ArrayElement", "taint", "manual"] # Implemented in QL because variadic arguments as outputs aren't supported in this format yet

go/ql/lib/go.qll

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import semmle.go.frameworks.Afero
3232
import semmle.go.frameworks.AwsLambda
3333
import semmle.go.frameworks.Beego
3434
import semmle.go.frameworks.BeegoOrm
35+
import semmle.go.frameworks.Bun
3536
import semmle.go.frameworks.RsCors
3637
import semmle.go.frameworks.Couchbase
3738
import semmle.go.frameworks.Echo
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `Bun` package.
3+
*/
4+
5+
import go
6+
7+
/**
8+
* Provides classes modeling security-relevant aspects of the `Bun` package.
9+
*/
10+
private module Bun {
11+
private string packagePath() { result = package("github.com/uptrace/bun", "") }
12+
13+
private class RawQuerySources extends SourceNode {
14+
RawQuerySources() {
15+
// func (q *RawQuery) Exec(ctx context.Context, dest ...interface{}) (sql.Result, error)
16+
// func (q *RawQuery) Scan(ctx context.Context, dest ...interface{}) error
17+
exists(DataFlow::CallNode cn, int i |
18+
cn.getTarget().(Method).hasQualifiedName(packagePath(), "RawQuery", ["Exec", "Scan"]) and
19+
i >= 1
20+
|
21+
this = cn.getSyntacticArgument(i)
22+
)
23+
}
24+
25+
override string getThreatModel() { result = "database" }
26+
}
27+
28+
private class SelectQuerySources extends SourceNode {
29+
SelectQuerySources() {
30+
// func (q *SelectQuery) Exec(ctx context.Context, dest ...interface{}) (res sql.Result, err error)
31+
// func (q *SelectQuery) Scan(ctx context.Context, dest ...interface{}) error
32+
// func (q *SelectQuery) ScanAndCount(ctx context.Context, dest ...interface{}) (int, error)
33+
exists(DataFlow::CallNode cn, int i |
34+
cn.getTarget()
35+
.(Method)
36+
.hasQualifiedName(packagePath(), "SelectQuery", ["Exec", "Scan", "ScanAndCount"]) and
37+
i >= 1
38+
|
39+
this = cn.getSyntacticArgument(i)
40+
)
41+
}
42+
43+
override string getThreatModel() { result = "database" }
44+
}
45+
46+
private class DBScanRows extends TaintTracking::FunctionModel, Method {
47+
FunctionInput inp;
48+
FunctionOutput outp;
49+
50+
DBScanRows() {
51+
// func (db *DB) ScanRow(ctx context.Context, rows *sql.Rows, dest ...interface{}) error
52+
// func (db *DB) ScanRows(ctx context.Context, rows *sql.Rows, dest ...interface{}) error
53+
this.hasQualifiedName(packagePath(), "DB", ["ScanRow", "ScanRows"]) and
54+
inp.isParameter(1) and
55+
outp.isParameter(any(int i | i >= 2))
56+
}
57+
58+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
59+
input = inp and output = outp
60+
}
61+
}
62+
}

go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/database/go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ require (
77
github.com/beego/beego/v2 v2.3.5
88
github.com/couchbase/gocb v1.6.7
99
github.com/couchbase/gocb/v2 v2.9.4
10+
github.com/gogf/gf v1.16.9
1011
github.com/jmoiron/sqlx v1.4.0
1112
github.com/Masterminds/squirrel v1.5.4
1213
github.com/rqlite/gorqlite v0.0.0-20250128004930-114c7828b55a
14+
github.com/uptrace/bun v1.2.11
1315
go.mongodb.org/mongo-driver v1.17.3
1416
gorm.io/gorm v1.25.12
15-
github.com/nonexistent/sources v0.0.0-20250300000000-000000000000
1617
)
1718

1819
require (

go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/database/source.ext.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ extensions:
88
pack: codeql/go-all
99
extensible: sourceModel
1010
data:
11-
- ["github.com/nonexistent/sources", "", False, "Source", "", "", "ReturnValue", "database", "manual"]
11+
- ["test", "", False, "Source", "", "", "ReturnValue", "database", "manual"]

go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/database/test.ext.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ extensions:
1010
pack: codeql/go-all
1111
extensible: sourceModel
1212
data:
13-
- ["github.com/nonexistent/sources", "", False, "Source", "", "", "ReturnValue", "database", "manual"]
13+
- ["test", "", False, "Source", "", "", "ReturnValue", "database", "manual"]

go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/database/test_Masterminds_squirrel.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ import (
66
"context"
77

88
"github.com/Masterminds/squirrel"
9-
src "github.com/nonexistent/sources"
109
)
1110

11+
func Source[T any]() T {
12+
return *new(T)
13+
}
14+
1215
func test_Masterminds_squirrel_QueryRower(ctx context.Context, db squirrel.QueryRower, sqlizer squirrel.Sqlizer) {
1316
scanner := db.QueryRow("") // $ source
1417

@@ -136,7 +139,7 @@ func test_Masterminds_squirrel_DeleteBuilder(ctx context.Context, builder squirr
136139
sink(r32) // $ hasTaintFlow="r32"
137140
sink(r33) // $ hasTaintFlow="r33"
138141

139-
builder2 := src.Source[squirrel.DeleteBuilder]() // $ source
142+
builder2 := Source[squirrel.DeleteBuilder]() // $ source
140143

141144
var r41, r42, r43 string
142145
builder2.ScanContext(ctx, &r41, &r42, &r43)
@@ -177,7 +180,7 @@ func test_Masterminds_squirrel_InsertBuilder(ctx context.Context, builder squirr
177180
sink(r42) // $ hasTaintFlow="r42"
178181
sink(r43) // $ hasTaintFlow="r43"
179182

180-
builder2 := src.Source[squirrel.InsertBuilder]() // $ source
183+
builder2 := Source[squirrel.InsertBuilder]() // $ source
181184

182185
var r51, r52, r53 string
183186
builder2.Scan(&r51, &r52, &r53)
@@ -225,7 +228,7 @@ func test_Masterminds_squirrel_SelectBuilder(ctx context.Context, builder squirr
225228
sink(r42) // $ hasTaintFlow="r42"
226229
sink(r43) // $ hasTaintFlow="r43"
227230

228-
builder2 := src.Source[squirrel.SelectBuilder]() // $ source
231+
builder2 := Source[squirrel.SelectBuilder]() // $ source
229232

230233
var r51, r52, r53 string
231234
builder2.Scan(&r51, &r52, &r53)
@@ -273,7 +276,7 @@ func test_Masterminds_squirrel_UpdateBuilder(ctx context.Context, builder squirr
273276
sink(r42) // $ hasTaintFlow="r42"
274277
sink(r43) // $ hasTaintFlow="r43"
275278

276-
builder2 := src.Source[squirrel.UpdateBuilder]() // $ source
279+
builder2 := Source[squirrel.UpdateBuilder]() // $ source
277280

278281
var r51, r52, r53 string
279282
builder2.Scan(&r51, &r52, &r53)

0 commit comments

Comments
 (0)