Skip to content

Commit 1687042

Browse files
committed
Add Bun models and tests
1 parent ddb7da4 commit 1687042

File tree

4 files changed

+186
-17
lines changed

4 files changed

+186
-17
lines changed

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

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,19 @@ extensions:
33
pack: codeql/go-all
44
extensible: sourceModel
55
data:
6-
- ["github.com/uptrace/bun", "AddColumnQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
7-
- ["github.com/uptrace/bun", "CreateIndexQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
8-
- ["github.com/uptrace/bun", "CreateTableQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
9-
- ["github.com/uptrace/bun", "DeleteQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
10-
- ["github.com/uptrace/bun", "DropIndexQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
11-
- ["github.com/uptrace/bun", "DropTableQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
12-
- ["github.com/uptrace/bun", "InsertQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
13-
- ["github.com/uptrace/bun", "MergeQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
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
1413
- ["github.com/uptrace/bun", "SelectQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
15-
- ["github.com/uptrace/bun", "TruncateQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
16-
- ["github.com/uptrace/bun", "UpdateQuery", True, "Model", "", "", "Argument[0]", "database", "manual"]
17-
- ["github.com/uptrace/bun", "DeleteQuery", True, "Scan", "", "", "Argument[0]", "database", "manual"]
18-
- ["github.com/uptrace/bun", "InsertQuery", True, "Scan", "", "", "Argument[0]", "database", "manual"]
19-
- ["github.com/uptrace/bun", "MergeQuery", True, "Scan", "", "", "Argument[0]", "database", "manual"]
20-
- ["github.com/uptrace/bun", "RawQuery", True, "Scan", "", "", "Argument[0]", "database", "manual"]
21-
- ["github.com/uptrace/bun", "SelectQuery", True, "Scan", "", "", "Argument[0]", "database", "manual"]
22-
- ["github.com/uptrace/bun", "TruncateQuery", True, "Scan", "", "", "Argument[0]", "database", "manual"]
23-
- ["github.com/uptrace/bun", "UpdateQuery", True, "Scan", "", "", "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"]
2419
- addsTo:
2520
pack: codeql/go-all
2621
extensible: sinkModel
@@ -88,3 +83,9 @@ extensions:
8883
- ["github.com/uptrace/bun", "UpdateQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
8984
- ["github.com/uptrace/bun", "UpdateQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
9085
- ["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

Lines changed: 1 addition & 0 deletions
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
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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+
// private class BuilderScan extends TaintTracking::FunctionModel, Method {
63+
// FunctionInput inp;
64+
// FunctionOutput outp;
65+
// BuilderScan() {
66+
// // signature: func (b {Insert,Delete,Select,Update}Builder) Scan(dest ...interface{}) error
67+
// this.hasQualifiedName(packagePath(),
68+
// ["DeleteBuilder", "InsertBuilder", "SelectBuilder", "UpdateBuilder"], "Scan") and
69+
// inp.isReceiver() and
70+
// outp.isParameter(_)
71+
// }
72+
// override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
73+
// input = inp and output = outp
74+
// }
75+
// }
76+
// private class BuilderScanContext extends TaintTracking::FunctionModel, Method {
77+
// FunctionInput inp;
78+
// FunctionOutput outp;
79+
// BuilderScanContext() {
80+
// // signature: func (b {Insert,Delete,Select,Update}Builder) ScanContext(ctx context.Context, dest ...interface{}) error
81+
// this.hasQualifiedName(packagePath(),
82+
// ["DeleteBuilder", "InsertBuilder", "SelectBuilder", "UpdateBuilder"], "ScanContext") and
83+
// inp.isReceiver() and
84+
// exists(int i | i > 0 | outp.isParameter(i))
85+
// }
86+
// override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
87+
// input = inp and output = outp
88+
// }
89+
// }
90+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package test
2+
3+
//go:generate depstubber -vendor github.com/uptrace/bun Conn,DB,RawQuery,SelectQuery,Tx
4+
5+
import (
6+
"context"
7+
8+
"github.com/uptrace/bun"
9+
)
10+
11+
func Test_bun_conn(conn bun.Conn) {
12+
ctx := context.Background()
13+
14+
rows1, _ := conn.QueryContext(ctx, "SELECT * FROM users") // $ source
15+
conn.QueryRowContext(ctx, "SELECT * FROM users") // $ source
16+
17+
ignore(rows1)
18+
}
19+
20+
func Test_bun_db(db bun.DB) {
21+
ctx := context.Background()
22+
23+
rows1, _ := db.Query("SELECT * FROM users") // $ source
24+
25+
for rows1.Next() {
26+
var user User
27+
db.ScanRow(ctx, rows1, &user)
28+
sink(user) // $ hasTaintFlow="user"
29+
}
30+
31+
rows2, _ := db.QueryContext(ctx, "SELECT * FROM users") // $ source
32+
var users []User
33+
34+
db.ScanRows(ctx, rows2, &users)
35+
sink(users) // $ hasTaintFlow="users"
36+
37+
db.QueryRow("SELECT * FROM users") // $ source
38+
db.QueryRowContext(ctx, "SELECT * FROM users") // $ source
39+
}
40+
41+
func Test_bun_rawquery(q bun.RawQuery) {
42+
ctx := context.Background()
43+
44+
var u1 []User
45+
q.Exec(ctx, &u1) // $ source
46+
var u2 []User
47+
q.Scan(ctx, &u2) // $ source
48+
}
49+
50+
func Test_bun_selectquery(q bun.SelectQuery) {
51+
ctx := context.Background()
52+
53+
rows, _ := q.Rows(ctx) // $ source
54+
var u1 []User
55+
q.Exec(ctx, &u1) // $ source
56+
var u2 []User
57+
q.Model(&u2).Scan(ctx) // $ source
58+
var u3 map[string]interface{}
59+
q.Scan(ctx, &u3) // $ source
60+
var u4 []User
61+
q.Model(&u4).ScanAndCount(ctx) // $ source
62+
var u5 map[string]interface{}
63+
q.ScanAndCount(ctx, &u5) // $ source
64+
65+
ignore(rows)
66+
}
67+
68+
func Test_bun_tx(tx bun.Tx) {
69+
ctx := context.Background()
70+
71+
rows1, _ := tx.Query("SELECT * FROM users") // $ source
72+
rows2, _ := tx.QueryContext(ctx, "SELECT * FROM users") // $ source
73+
tx.QueryRow("SELECT * FROM users") // $ source
74+
tx.QueryRowContext(ctx, "SELECT * FROM users") // $ source
75+
76+
ignore(rows1, rows2)
77+
}

0 commit comments

Comments
 (0)