Move and extend Log module for package log with taint-tracking

This commit is contained in:
Slavomir
2020-09-15 17:04:25 +02:00
parent c61881acb3
commit bff19d5a37
3 changed files with 368 additions and 19 deletions

View File

@@ -37,6 +37,7 @@ import semmle.go.frameworks.stdlib.NetHttp
import semmle.go.frameworks.stdlib.NetHttpHttputil
import semmle.go.frameworks.stdlib.NetMail
import semmle.go.frameworks.stdlib.NetTextproto
import semmle.go.frameworks.stdlib.Log
import semmle.go.frameworks.stdlib.Path
import semmle.go.frameworks.stdlib.PathFilepath
import semmle.go.frameworks.stdlib.Reflect
@@ -481,31 +482,67 @@ module URL {
}
}
/** Provides models of commonly used functions in the `log` package. */
module Log {
private class LogCall extends LoggerCall::Range, DataFlow::CallNode {
LogCall() {
exists(string fn |
fn.matches("Fatal%")
or
fn.matches("Panic%")
or
fn.matches("Print%")
|
this.getTarget().hasQualifiedName("log", fn)
or
this.getTarget().(Method).hasQualifiedName("log", "Logger", fn)
/** Provides models of commonly used APIs in the `regexp` package. */
module Regexp {
private class Pattern extends RegexpPattern::Range, DataFlow::ArgumentNode {
string fnName;
Pattern() {
exists(Function fn | fnName.matches("Match%") or fnName.matches("%Compile%") |
fn.hasQualifiedName("regexp", fnName) and
this = fn.getACall().getArgument(0)
)
}
override DataFlow::Node getAMessageComponent() { result = this.getAnArgument() }
override DataFlow::Node getAParse() { result = this.getCall() }
override string getPattern() { result = this.asExpr().getStringValue() }
override DataFlow::Node getAUse() {
fnName.matches("MustCompile%") and
result = this.getCall().getASuccessor*()
or
fnName.matches("Compile%") and
result = this.getCall().getResult(0).getASuccessor*()
or
result = this
}
}
/** A fatal log function, which calls `os.Exit`. */
private class FatalLogFunction extends Function {
FatalLogFunction() { exists(string fn | fn.matches("Fatal%") | hasQualifiedName("log", fn)) }
private class MatchFunction extends RegexpMatchFunction::Range, Function {
MatchFunction() {
exists(string fn | fn.matches("Match%") | this.hasQualifiedName("regexp", fn))
}
override predicate mayReturnNormally() { none() }
override FunctionInput getRegexpArg() { result.isParameter(0) }
override FunctionInput getValue() { result.isParameter(1) }
override FunctionOutput getResult() { result.isResult(0) }
}
private class MatchMethod extends RegexpMatchFunction::Range, Method {
MatchMethod() {
exists(string fn | fn.matches("Match%") | this.hasQualifiedName("regexp", "Regexp", fn))
}
override FunctionInput getRegexpArg() { result.isReceiver() }
override FunctionInput getValue() { result.isParameter(0) }
override FunctionOutput getResult() { result.isResult() }
}
private class ReplaceFunction extends RegexpReplaceFunction::Range, Method {
ReplaceFunction() {
exists(string fn | fn.matches("ReplaceAll%") | this.hasQualifiedName("regexp", "Regexp", fn))
}
override FunctionInput getRegexpArg() { result.isReceiver() }
override FunctionInput getSource() { result.isParameter(0) }
override FunctionOutput getResult() { result.isResult() }
}
}

View File

@@ -0,0 +1,107 @@
/**
* Provides classes modeling security-relevant aspects of the `log` package.
*/
import go
/** Provides models of commonly used functions in the `log` package. */
module Log {
private class LogCall extends LoggerCall::Range, DataFlow::CallNode {
LogCall() {
exists(string fn |
fn.matches("Fatal%")
or
fn.matches("Panic%")
or
fn.matches("Print%")
|
this.getTarget().hasQualifiedName("log", fn)
or
this.getTarget().(Method).hasQualifiedName("log", "Logger", fn)
)
}
override DataFlow::Node getAMessageComponent() { result = this.getAnArgument() }
}
/** A fatal log function, which calls `os.Exit`. */
private class FatalLogFunction extends Function {
FatalLogFunction() { exists(string fn | fn.matches("Fatal%") | hasQualifiedName("log", fn)) }
override predicate mayReturnNormally() { none() }
}
private class FunctionModels extends TaintTracking::FunctionModel {
FunctionInput inp;
FunctionOutput outp;
FunctionModels() {
// signature: func New(out io.Writer, prefix string, flag int) *Logger
hasQualifiedName("log", "New") and
(inp.isResult() and outp.isParameter(0))
}
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 (*Logger).Fatal(v ...interface{})
this.hasQualifiedName("log", "Logger", "Fatal") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger).Fatalf(format string, v ...interface{})
this.hasQualifiedName("log", "Logger", "Fatalf") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger).Fatalln(v ...interface{})
this.hasQualifiedName("log", "Logger", "Fatalln") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger).Panic(v ...interface{})
this.hasQualifiedName("log", "Logger", "Panic") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger).Panicf(format string, v ...interface{})
this.hasQualifiedName("log", "Logger", "Panicf") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger).Panicln(v ...interface{})
this.hasQualifiedName("log", "Logger", "Panicln") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger).Print(v ...interface{})
this.hasQualifiedName("log", "Logger", "Print") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger).Printf(format string, v ...interface{})
this.hasQualifiedName("log", "Logger", "Printf") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger).Println(v ...interface{})
this.hasQualifiedName("log", "Logger", "Println") and
(inp.isParameter(_) and outp.isReceiver())
or
// signature: func (*Logger).SetOutput(w io.Writer)
this.hasQualifiedName("log", "Logger", "SetOutput") and
(inp.isReceiver() and outp.isParameter(0))
or
// signature: func (*Logger).SetPrefix(prefix string)
this.hasQualifiedName("log", "Logger", "SetPrefix") and
(inp.isParameter(0) and outp.isReceiver())
or
// signature: func (*Logger).Writer() io.Writer
this.hasQualifiedName("log", "Logger", "Writer") and
(inp.isResult() and outp.isReceiver())
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input = inp and output = outp
}
}
}

View File

@@ -0,0 +1,205 @@
// Code generated by https://github.com/gagliardetto/codebox. DO NOT EDIT.
package main
import (
"io"
"log"
)
func TaintStepTest_LogNew_B0I0O0(sourceCQL interface{}) interface{} {
fromLogger656 := sourceCQL.(*log.Logger)
var intoWriter414 io.Writer
intermediateCQL := log.New(intoWriter414, "", 0)
link(fromLogger656, intermediateCQL)
return intoWriter414
}
func TaintStepTest_LogLoggerFatal_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface518 := sourceCQL.(interface{})
var intoLogger650 log.Logger
intoLogger650.Fatal(fromInterface518)
return intoLogger650
}
func TaintStepTest_LogLoggerFatalf_B0I0O0(sourceCQL interface{}) interface{} {
fromString784 := sourceCQL.(string)
var intoLogger957 log.Logger
intoLogger957.Fatalf(fromString784, nil)
return intoLogger957
}
func TaintStepTest_LogLoggerFatalf_B0I1O0(sourceCQL interface{}) interface{} {
fromInterface520 := sourceCQL.(interface{})
var intoLogger443 log.Logger
intoLogger443.Fatalf("", fromInterface520)
return intoLogger443
}
func TaintStepTest_LogLoggerFatalln_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface127 := sourceCQL.(interface{})
var intoLogger483 log.Logger
intoLogger483.Fatalln(fromInterface127)
return intoLogger483
}
func TaintStepTest_LogLoggerPanic_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface989 := sourceCQL.(interface{})
var intoLogger982 log.Logger
intoLogger982.Panic(fromInterface989)
return intoLogger982
}
func TaintStepTest_LogLoggerPanicf_B0I0O0(sourceCQL interface{}) interface{} {
fromString417 := sourceCQL.(string)
var intoLogger584 log.Logger
intoLogger584.Panicf(fromString417, nil)
return intoLogger584
}
func TaintStepTest_LogLoggerPanicf_B0I1O0(sourceCQL interface{}) interface{} {
fromInterface991 := sourceCQL.(interface{})
var intoLogger881 log.Logger
intoLogger881.Panicf("", fromInterface991)
return intoLogger881
}
func TaintStepTest_LogLoggerPanicln_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface186 := sourceCQL.(interface{})
var intoLogger284 log.Logger
intoLogger284.Panicln(fromInterface186)
return intoLogger284
}
func TaintStepTest_LogLoggerPrint_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface908 := sourceCQL.(interface{})
var intoLogger137 log.Logger
intoLogger137.Print(fromInterface908)
return intoLogger137
}
func TaintStepTest_LogLoggerPrintf_B0I0O0(sourceCQL interface{}) interface{} {
fromString494 := sourceCQL.(string)
var intoLogger873 log.Logger
intoLogger873.Printf(fromString494, nil)
return intoLogger873
}
func TaintStepTest_LogLoggerPrintf_B0I1O0(sourceCQL interface{}) interface{} {
fromInterface599 := sourceCQL.(interface{})
var intoLogger409 log.Logger
intoLogger409.Printf("", fromInterface599)
return intoLogger409
}
func TaintStepTest_LogLoggerPrintln_B0I0O0(sourceCQL interface{}) interface{} {
fromInterface246 := sourceCQL.(interface{})
var intoLogger898 log.Logger
intoLogger898.Println(fromInterface246)
return intoLogger898
}
func TaintStepTest_LogLoggerSetOutput_B0I0O0(sourceCQL interface{}) interface{} {
fromLogger598 := sourceCQL.(log.Logger)
var intoWriter631 io.Writer
fromLogger598.SetOutput(intoWriter631)
return intoWriter631
}
func TaintStepTest_LogLoggerSetPrefix_B0I0O0(sourceCQL interface{}) interface{} {
fromString165 := sourceCQL.(string)
var intoLogger150 log.Logger
intoLogger150.SetPrefix(fromString165)
return intoLogger150
}
func TaintStepTest_LogLoggerWriter_B0I0O0(sourceCQL interface{}) interface{} {
fromWriter340 := sourceCQL.(io.Writer)
var intoLogger471 log.Logger
intermediateCQL := intoLogger471.Writer()
link(fromWriter340, intermediateCQL)
return intoLogger471
}
func RunAllTaints_Log() {
{
source := newSource(0)
out := TaintStepTest_LogNew_B0I0O0(source)
sink(0, out)
}
{
source := newSource(1)
out := TaintStepTest_LogLoggerFatal_B0I0O0(source)
sink(1, out)
}
{
source := newSource(2)
out := TaintStepTest_LogLoggerFatalf_B0I0O0(source)
sink(2, out)
}
{
source := newSource(3)
out := TaintStepTest_LogLoggerFatalf_B0I1O0(source)
sink(3, out)
}
{
source := newSource(4)
out := TaintStepTest_LogLoggerFatalln_B0I0O0(source)
sink(4, out)
}
{
source := newSource(5)
out := TaintStepTest_LogLoggerPanic_B0I0O0(source)
sink(5, out)
}
{
source := newSource(6)
out := TaintStepTest_LogLoggerPanicf_B0I0O0(source)
sink(6, out)
}
{
source := newSource(7)
out := TaintStepTest_LogLoggerPanicf_B0I1O0(source)
sink(7, out)
}
{
source := newSource(8)
out := TaintStepTest_LogLoggerPanicln_B0I0O0(source)
sink(8, out)
}
{
source := newSource(9)
out := TaintStepTest_LogLoggerPrint_B0I0O0(source)
sink(9, out)
}
{
source := newSource(10)
out := TaintStepTest_LogLoggerPrintf_B0I0O0(source)
sink(10, out)
}
{
source := newSource(11)
out := TaintStepTest_LogLoggerPrintf_B0I1O0(source)
sink(11, out)
}
{
source := newSource(12)
out := TaintStepTest_LogLoggerPrintln_B0I0O0(source)
sink(12, out)
}
{
source := newSource(13)
out := TaintStepTest_LogLoggerSetOutput_B0I0O0(source)
sink(13, out)
}
{
source := newSource(14)
out := TaintStepTest_LogLoggerSetPrefix_B0I0O0(source)
sink(14, out)
}
{
source := newSource(15)
out := TaintStepTest_LogLoggerWriter_B0I0O0(source)
sink(15, out)
}
}