Upgrade and convert gorqlite sql-injection sinks to MaD

This commit is contained in:
Owen Mansel-Chan
2024-08-15 12:25:24 +01:00
parent 06f86dd22f
commit ce0cb12c29
10 changed files with 245 additions and 45 deletions

View File

@@ -0,0 +1,35 @@
extensions:
- addsTo:
pack: codeql/go-all
extensible: packageGrouping
data:
- ["gorqlite", "github.com/rqlite/gorqlite"]
- ["gorqlite", "github.com/raindog308/gorqlite"]
- addsTo:
pack: codeql/go-all
extensible: sinkModel
data:
- ["group:gorqlite", "Connection", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueryOne", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueryOneContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueryOneParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueryOneParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueryParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueryParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "Queue", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueueContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueueOne", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueueOneContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueueOneParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueueOneParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueueParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "QueueParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "Write", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "WriteContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "WriteOne", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "WriteOneContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "WriteOneParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "WriteOneParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "WriteParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
- ["group:gorqlite", "Connection", True, "WriteParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]

View File

@@ -85,11 +85,6 @@ module SQL {
/** A string that might identify package `go-pg/pg/orm` or a specific version of it. */
private string gopgorm() { result = package("github.com/go-pg/pg", "orm") }
/** A string that might identify package `github.com/rqlite/gorqlite` or `github.com/raindog308/gorqlite` or a specific version of it. */
private string gorqlite() {
result = package(["github.com/rqlite/gorqlite", "github.com/raindog308/gorqlite"], "")
}
/** A string that might identify package `github.com/gogf/gf/database/gdb` or a specific version of it. */
private string gogf() { result = package("github.com/gogf/gf", "database/gdb") }
@@ -158,25 +153,6 @@ module SQL {
}
}
/**
* A string argument to an API of `github.com/rqlite/gorqlite`, or a specific version of it, that is directly interpreted as SQL without
* taking syntactic structure into account.
*/
private class GorqliteQueryString extends Range {
GorqliteQueryString() {
// func (conn *Connection) Query(sqlStatements []string) (results []QueryResult, err error)
// func (conn *Connection) QueryOne(sqlStatement string) (qr QueryResult, err error)
// func (conn *Connection) Queue(sqlStatements []string) (seq int64, err error)
// func (conn *Connection) QueueOne(sqlStatement string) (seq int64, err error)
// func (conn *Connection) Write(sqlStatements []string) (results []WriteResult, err error)
// func (conn *Connection) WriteOne(sqlStatement string) (wr WriteResult, err error)
exists(Method m, string name | m.hasQualifiedName(gorqlite(), "Connection", name) |
name = ["Query", "QueryOne", "Queue", "QueueOne", "Write", "WriteOne"] and
this = m.getACall().getArgument(0)
)
}
}
/**
* A string argument to an API of `github.com/gogf/gf/database/gdb`, or a specific version of it, that is directly interpreted as SQL without
* taking syntactic structure into account.

View File

@@ -0,0 +1,3 @@
testFailures
invalidModelRow
failures

View File

@@ -0,0 +1,60 @@
import go
import semmle.go.dataflow.ExternalFlow
import ModelValidation
import TestUtilities.InlineExpectationsTest
module SqlTest implements TestSig {
string getARelevantTag() { result = "query" }
predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "query" and
exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() |
q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
element = q.toString() and
value = qs.toString()
)
}
}
module QueryString implements TestSig {
string getARelevantTag() { result = "querystring" }
predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "querystring" and
element = "" and
exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) |
qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
value = qs.toString()
)
}
}
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit }
predicate isSink(DataFlow::Node n) {
n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument()
}
}
module Flow = TaintTracking::Global<Config>;
module TaintFlow implements TestSig {
string getARelevantTag() { result = "flowfrom" }
predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "flowfrom" and
element = "" and
exists(DataFlow::Node fromNode, DataFlow::Node toNode |
toNode
.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
Flow::flow(fromNode, toNode) and
value = fromNode.asExpr().(StringLit).getValue()
)
}
}
import MakeTest<MergeTests3<SqlTest, QueryString, TaintFlow>>

View File

@@ -2,4 +2,4 @@ module main
go 1.18
require github.com/rqlite/gorqlite v0.0.0-20220528150909-c4e99ae96be6
require github.com/rqlite/gorqlite v0.0.0-20240808172217-12ae7d03ef19

View File

@@ -1,6 +0,0 @@
| gorqlite.go:11:13:11:16 | sqls |
| gorqlite.go:12:13:12:16 | sqls |
| gorqlite.go:13:13:13:16 | sqls |
| gorqlite.go:14:16:14:18 | sql |
| gorqlite.go:15:16:15:18 | sql |
| gorqlite.go:16:16:16:18 | sql |

View File

@@ -1,20 +1,49 @@
package main
//go:generate depstubber -vendor github.com/rqlite/gorqlite Connection Open
//go:generate depstubber -vendor github.com/rqlite/gorqlite Connection,ParameterizedStatement Open
import (
"context"
"github.com/rqlite/gorqlite"
)
func gorqlitetest(sql string, sqls []string) {
func gorqlitetest(sql string, sqls []string, param_sql gorqlite.ParameterizedStatement, param_sqls []gorqlite.ParameterizedStatement, ctx context.Context) {
conn, _ := gorqlite.Open("dbUrl")
conn.Query(sqls) // $ querystring=sqls
conn.Queue(sqls) // $ querystring=sqls
conn.Write(sqls) // $ querystring=sqls
conn.Query(sqls) // $ querystring=sqls
conn.Queue(sqls) // $ querystring=sqls
conn.Write(sqls) // $ querystring=sqls
conn.QueryOne(sql) // $ querystring=sql
conn.QueueOne(sql) // $ querystring=sql
conn.WriteOne(sql) // $ querystring=sql
conn.QueryParameterized(param_sqls) // $ querystring=param_sqls
conn.QueueParameterized(param_sqls) // $ querystring=param_sqls
conn.WriteParameterized(param_sqls) // $ querystring=param_sqls
conn.QueryOneParameterized(param_sql) // $ querystring=param_sql
conn.QueueOneParameterized(param_sql) // $ querystring=param_sql
conn.WriteOneParameterized(param_sql) // $ querystring=param_sql
conn.QueryContext(ctx, sqls) // $ querystring=sqls
conn.QueueContext(ctx, sqls) // $ querystring=sqls
conn.WriteContext(ctx, sqls) // $ querystring=sqls
conn.QueryOneContext(ctx, sql) // $ querystring=sql
conn.QueueOneContext(ctx, sql) // $ querystring=sql
conn.WriteOneContext(ctx, sql) // $ querystring=sql
conn.QueryParameterizedContext(ctx, param_sqls) // $ querystring=param_sqls
conn.QueueParameterizedContext(ctx, param_sqls) // $ querystring=param_sqls
conn.WriteParameterizedContext(ctx, param_sqls) // $ querystring=param_sqls
conn.QueryOneParameterizedContext(ctx, param_sql) // $ querystring=param_sql
conn.QueueOneParameterizedContext(ctx, param_sql) // $ querystring=param_sql
conn.WriteOneParameterizedContext(ctx, param_sql) // $ querystring=param_sql
}
func main() {
return
}

View File

@@ -1,4 +0,0 @@
import go
from SQL::QueryString qs
select qs

View File

@@ -2,11 +2,15 @@
// This is a simple stub for github.com/rqlite/gorqlite, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/rqlite/gorqlite (exports: Connection; functions: Open)
// Source: github.com/rqlite/gorqlite (exports: Connection,ParameterizedStatement; functions: Open)
// Package gorqlite is a stub of github.com/rqlite/gorqlite, generated by depstubber.
package gorqlite
import (
context "context"
)
type Connection struct {
ID string
}
@@ -29,19 +33,83 @@ func (_ *Connection) Query(_ []string) ([]QueryResult, error) {
return nil, nil
}
func (_ *Connection) QueryContext(_ context.Context, _ []string) ([]QueryResult, error) {
return nil, nil
}
func (_ *Connection) QueryOne(_ string) (QueryResult, error) {
return QueryResult{}, nil
}
func (_ *Connection) QueryOneContext(_ context.Context, _ string) (QueryResult, error) {
return QueryResult{}, nil
}
func (_ *Connection) QueryOneParameterized(_ ParameterizedStatement) (QueryResult, error) {
return QueryResult{}, nil
}
func (_ *Connection) QueryOneParameterizedContext(_ context.Context, _ ParameterizedStatement) (QueryResult, error) {
return QueryResult{}, nil
}
func (_ *Connection) QueryParameterized(_ []ParameterizedStatement) ([]QueryResult, error) {
return nil, nil
}
func (_ *Connection) QueryParameterizedContext(_ context.Context, _ []ParameterizedStatement) ([]QueryResult, error) {
return nil, nil
}
func (_ *Connection) Queue(_ []string) (int64, error) {
return 0, nil
}
func (_ *Connection) QueueContext(_ context.Context, _ []string) (int64, error) {
return 0, nil
}
func (_ *Connection) QueueOne(_ string) (int64, error) {
return 0, nil
}
func (_ *Connection) SetConsistencyLevel(_ string) error {
func (_ *Connection) QueueOneContext(_ context.Context, _ string) (int64, error) {
return 0, nil
}
func (_ *Connection) QueueOneParameterized(_ ParameterizedStatement) (int64, error) {
return 0, nil
}
func (_ *Connection) QueueOneParameterizedContext(_ context.Context, _ ParameterizedStatement) (int64, error) {
return 0, nil
}
func (_ *Connection) QueueParameterized(_ []ParameterizedStatement) (int64, error) {
return 0, nil
}
func (_ *Connection) QueueParameterizedContext(_ context.Context, _ []ParameterizedStatement) (int64, error) {
return 0, nil
}
func (_ *Connection) Request(_ []string) ([]RequestResult, error) {
return nil, nil
}
func (_ *Connection) RequestContext(_ context.Context, _ []string) ([]RequestResult, error) {
return nil, nil
}
func (_ *Connection) RequestParameterized(_ []ParameterizedStatement) ([]RequestResult, error) {
return nil, nil
}
func (_ *Connection) RequestParameterizedContext(_ context.Context, _ []ParameterizedStatement) ([]RequestResult, error) {
return nil, nil
}
func (_ *Connection) SetConsistencyLevel(_ interface{}) error {
return nil
}
@@ -53,12 +121,41 @@ func (_ *Connection) Write(_ []string) ([]WriteResult, error) {
return nil, nil
}
func (_ *Connection) WriteContext(_ context.Context, _ []string) ([]WriteResult, error) {
return nil, nil
}
func (_ *Connection) WriteOne(_ string) (WriteResult, error) {
return WriteResult{}, nil
}
func Open(_ string) (Connection, error) {
return Connection{}, nil
func (_ *Connection) WriteOneContext(_ context.Context, _ string) (WriteResult, error) {
return WriteResult{}, nil
}
func (_ *Connection) WriteOneParameterized(_ ParameterizedStatement) (WriteResult, error) {
return WriteResult{}, nil
}
func (_ *Connection) WriteOneParameterizedContext(_ context.Context, _ ParameterizedStatement) (WriteResult, error) {
return WriteResult{}, nil
}
func (_ *Connection) WriteParameterized(_ []ParameterizedStatement) ([]WriteResult, error) {
return nil, nil
}
func (_ *Connection) WriteParameterizedContext(_ context.Context, _ []ParameterizedStatement) ([]WriteResult, error) {
return nil, nil
}
func Open(_ string) (*Connection, error) {
return nil, nil
}
type ParameterizedStatement struct {
Query string
Arguments []interface{}
}
type QueryResult struct {
@@ -90,10 +187,20 @@ func (_ *QueryResult) Scan(_ ...interface{}) error {
return nil
}
func (_ *QueryResult) Slice() ([]interface{}, error) {
return nil, nil
}
func (_ *QueryResult) Types() []string {
return nil
}
type RequestResult struct {
Err error
Query *QueryResult
Write *WriteResult
}
type WriteResult struct {
Err error
Timing float64

View File

@@ -1,3 +1,3 @@
# github.com/rqlite/gorqlite v0.0.0-20220528150909-c4e99ae96be6
# github.com/rqlite/gorqlite v0.0.0-20240808172217-12ae7d03ef19
## explicit
github.com/rqlite/gorqlite