diff --git a/ql/src/semmle/go/frameworks/SQL.qll b/ql/src/semmle/go/frameworks/SQL.qll index ecb5becdfca..2a6d4e1804a 100644 --- a/ql/src/semmle/go/frameworks/SQL.qll +++ b/ql/src/semmle/go/frameworks/SQL.qll @@ -6,6 +6,48 @@ import go /** Provides classes for working with SQL-related APIs. */ module SQL { + private class FunctionModels extends TaintTracking::FunctionModel { + FunctionInput inp; + FunctionOutput outp; + + FunctionModels() { + // signature: func Named(name string, value interface{}) NamedArg + hasQualifiedName("database/sql", "Named") and + (inp.isParameter(_) and outp.isResult()) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = inp and output = outp + } + } + + private class MethodModels extends TaintTracking::FunctionModel, Method { + FunctionInput inp; + FunctionOutput outp; + + MethodModels() { + // signature: func (*NullString).Scan(value interface{}) error + this.hasQualifiedName("database/sql", "NullString", "Scan") and + (inp.isParameter(0) and outp.isReceiver()) + or + // signature: func (*Row).Scan(dest ...interface{}) error + this.hasQualifiedName("database/sql", "Row", "Scan") and + (inp.isReceiver() and outp.isParameter(_)) + or + // signature: func (*Rows).Scan(dest ...interface{}) error + this.hasQualifiedName("database/sql", "Rows", "Scan") and + (inp.isReceiver() and outp.isParameter(_)) + or + // signature: func (Scanner).Scan(src interface{}) error + this.implements("database/sql", "Scanner", "Scan") and + (inp.isParameter(0) and outp.isReceiver()) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = inp and output = outp + } + } + /** * A data-flow node whose string value is interpreted as (part of) a SQL query. * diff --git a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/DatabaseSql.go b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/DatabaseSql.go new file mode 100644 index 00000000000..a274702290a --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/DatabaseSql.go @@ -0,0 +1,78 @@ +// Code generated by https://github.com/gagliardetto/codebox. DO NOT EDIT. + +package main + +import "database/sql" + +func TaintStepTest_DatabaseSqlNamed_B0I0O0(sourceCQL interface{}) interface{} { + fromString656 := sourceCQL.(string) + intoNamedArg414 := sql.Named(fromString656, nil) + return intoNamedArg414 +} + +func TaintStepTest_DatabaseSqlNamed_B0I1O0(sourceCQL interface{}) interface{} { + fromInterface518 := sourceCQL.(interface{}) + intoNamedArg650 := sql.Named("", fromInterface518) + return intoNamedArg650 +} + +func TaintStepTest_DatabaseSqlNullStringScan_B0I0O0(sourceCQL interface{}) interface{} { + fromInterface784 := sourceCQL.(interface{}) + var intoNullString957 sql.NullString + intoNullString957.Scan(fromInterface784) + return intoNullString957 +} + +func TaintStepTest_DatabaseSqlRowScan_B0I0O0(sourceCQL interface{}) interface{} { + fromRow520 := sourceCQL.(sql.Row) + var intoInterface443 interface{} + fromRow520.Scan(intoInterface443) + return intoInterface443 +} + +func TaintStepTest_DatabaseSqlRowsScan_B0I0O0(sourceCQL interface{}) interface{} { + fromRows127 := sourceCQL.(sql.Rows) + var intoInterface483 interface{} + fromRows127.Scan(intoInterface483) + return intoInterface483 +} + +func TaintStepTest_DatabaseSqlScannerScan_B0I0O0(sourceCQL interface{}) interface{} { + fromInterface989 := sourceCQL.(interface{}) + var intoScanner982 sql.Scanner + intoScanner982.Scan(fromInterface989) + return intoScanner982 +} + +func RunAllTaints_DatabaseSql() { + { + source := newSource(0) + out := TaintStepTest_DatabaseSqlNamed_B0I0O0(source) + sink(0, out) + } + { + source := newSource(1) + out := TaintStepTest_DatabaseSqlNamed_B0I1O0(source) + sink(1, out) + } + { + source := newSource(2) + out := TaintStepTest_DatabaseSqlNullStringScan_B0I0O0(source) + sink(2, out) + } + { + source := newSource(3) + out := TaintStepTest_DatabaseSqlRowScan_B0I0O0(source) + sink(3, out) + } + { + source := newSource(4) + out := TaintStepTest_DatabaseSqlRowsScan_B0I0O0(source) + sink(4, out) + } + { + source := newSource(5) + out := TaintStepTest_DatabaseSqlScannerScan_B0I0O0(source) + sink(5, out) + } +}