diff --git a/ql/src/semmle/go/frameworks/Stdlib.qll b/ql/src/semmle/go/frameworks/Stdlib.qll index b43886d6307..cee1e59676d 100644 --- a/ql/src/semmle/go/frameworks/Stdlib.qll +++ b/ql/src/semmle/go/frameworks/Stdlib.qll @@ -29,6 +29,7 @@ import semmle.go.frameworks.stdlib.EncodingPem import semmle.go.frameworks.stdlib.EncodingXml import semmle.go.frameworks.stdlib.Html import semmle.go.frameworks.stdlib.HtmlTemplate +import semmle.go.frameworks.stdlib.Io import semmle.go.frameworks.stdlib.Path import semmle.go.frameworks.stdlib.PathFilepath import semmle.go.frameworks.stdlib.Reflect @@ -145,226 +146,6 @@ module Fmt { } } -/** Provides models of commonly used functions in the `io` package. */ -module Io { - private class Copy extends TaintTracking::FunctionModel { - Copy() { - // func Copy(dst Writer, src Reader) (written int64, err error) - // func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) - // func CopyN(dst Writer, src Reader, n int64) (written int64, err error) - hasQualifiedName("io", "Copy") or - hasQualifiedName("io", "CopyBuffer") or - hasQualifiedName("io", "CopyN") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(1) and output.isParameter(0) - } - } - - private class Pipe extends TaintTracking::FunctionModel { - Pipe() { - // func Pipe() (*PipeReader, *PipeWriter) - hasQualifiedName("io", "Pipe") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isResult(0) and output.isResult(1) - } - } - - private class ReadAtLeast extends TaintTracking::FunctionModel { - ReadAtLeast() { - // func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) - // func ReadFull(r Reader, buf []byte) (n int, err error) - hasQualifiedName("io", "ReadAtLeast") or - hasQualifiedName("io", "ReadFull") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(0) and output.isParameter(1) - } - } - - private class WriteString extends TaintTracking::FunctionModel { - WriteString() { - // func WriteString(w Writer, s string) (n int, err error) - this.hasQualifiedName("io", "WriteString") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(1) and output.isParameter(0) - } - } - - private class ByteReaderReadByte extends TaintTracking::FunctionModel, Method { - ByteReaderReadByte() { - // func ReadByte() (byte, error) - this.implements("io", "ByteReader", "ReadByte") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isReceiver() and output.isResult(0) - } - } - - private class ByteWriterWriteByte extends TaintTracking::FunctionModel, Method { - ByteWriterWriteByte() { - // func WriteByte(c byte) error - this.implements("io", "ByteWriter", "WriteByte") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(0) and output.isReceiver() - } - } - - private class ReaderRead extends TaintTracking::FunctionModel, Method { - ReaderRead() { - // func Read(p []byte) (n int, err error) - this.implements("io", "Reader", "Read") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isReceiver() and output.isParameter(0) - } - } - - private class LimitReader extends TaintTracking::FunctionModel { - LimitReader() { - // func LimitReader(r Reader, n int64) Reader - this.hasQualifiedName("io", "LimitReader") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(0) and output.isResult() - } - } - - private class MultiReader extends TaintTracking::FunctionModel { - MultiReader() { - // func MultiReader(readers ...Reader) Reader - this.hasQualifiedName("io", "MultiReader") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(_) and output.isResult() - } - } - - private class TeeReader extends TaintTracking::FunctionModel { - TeeReader() { - // func TeeReader(r Reader, w Writer) Reader - this.hasQualifiedName("io", "TeeReader") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(0) and output.isResult() - or - input.isParameter(0) and output.isParameter(1) - } - } - - private class ReaderAtReadAt extends TaintTracking::FunctionModel, Method { - ReaderAtReadAt() { - // func ReadAt(p []byte, off int64) (n int, err error) - this.implements("io", "ReaderAt", "ReadAt") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isReceiver() and output.isParameter(0) - } - } - - private class ReaderFromReadFrom extends TaintTracking::FunctionModel, Method { - ReaderFromReadFrom() { - // func ReadFrom(r Reader) (n int64, err error) - this.implements("io", "ReaderFrom", "ReadFrom") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(0) and output.isReceiver() - } - } - - private class RuneReaderReadRune extends TaintTracking::FunctionModel, Method { - RuneReaderReadRune() { - // func ReadRune() (r rune, size int, err error) - this.implements("io", "RuneReader", "ReadRune") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isReceiver() and output.isResult(0) - } - } - - private class NewSectionReader extends TaintTracking::FunctionModel { - NewSectionReader() { - // func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader - this.hasQualifiedName("io", "NewSectionReader") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(0) and output.isResult() - } - } - - private class StringWriterWriteString extends TaintTracking::FunctionModel, Method { - StringWriterWriteString() { - // func WriteString(s string) (n int, err error) - this.implements("io", "StringWriter", "WriteString") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(0) and output.isReceiver() - } - } - - private class WriterWrite extends TaintTracking::FunctionModel, Method { - WriterWrite() { - // func Write(p []byte) (n int, err error) - this.implements("io", "Writer", "Write") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(0) and output.isReceiver() - } - } - - private class MultiWriter extends TaintTracking::FunctionModel { - MultiWriter() { - // func MultiWriter(writers ...Writer) Writer - hasQualifiedName("io", "MultiWriter") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isResult() and output.isParameter(_) - } - } - - private class WriterAtWriteAt extends TaintTracking::FunctionModel, Method { - WriterAtWriteAt() { - // func WriteAt(p []byte, off int64) (n int, err error) - this.implements("io", "WriterAt", "WriteAt") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isParameter(0) and output.isReceiver() - } - } - - private class WriterToWriteTo extends TaintTracking::FunctionModel, Method { - WriterToWriteTo() { - // func WriteTo(w Writer) (n int64, err error) - this.implements("io", "WriterTo", "WriteTo") - } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - input.isReceiver() and output.isParameter(0) - } - } -} - /** Provides models of commonly used functions in the `io/ioutil` package. */ module IoUtil { private class IoUtilFileSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode { diff --git a/ql/src/semmle/go/frameworks/stdlib/Io.qll b/ql/src/semmle/go/frameworks/stdlib/Io.qll new file mode 100644 index 00000000000..b0015e29e29 --- /dev/null +++ b/ql/src/semmle/go/frameworks/stdlib/Io.qll @@ -0,0 +1,129 @@ +/** + * Provides classes modeling security-relevant aspects of the `io` package. + */ + +import go + +/** Provides models of commonly used functions in the `io` package. */ +module Io { + private class FunctionModels extends TaintTracking::FunctionModel { + FunctionInput inp; + FunctionOutput outp; + + FunctionModels() { + // signature: func Copy(dst Writer, src Reader) (written int64, err error) + hasQualifiedName("io", "Copy") and + (inp.isParameter(1) and outp.isParameter(0)) + or + // signature: func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) + hasQualifiedName("io", "CopyBuffer") and + (inp.isParameter(1) and outp.isParameter(0)) + or + // signature: func CopyN(dst Writer, src Reader, n int64) (written int64, err error) + hasQualifiedName("io", "CopyN") and + (inp.isParameter(1) and outp.isParameter(0)) + or + // signature: func LimitReader(r Reader, n int64) Reader + hasQualifiedName("io", "LimitReader") and + (inp.isParameter(0) and outp.isResult()) + or + // signature: func MultiReader(readers ...Reader) Reader + hasQualifiedName("io", "MultiReader") and + (inp.isParameter(_) and outp.isResult()) + or + // signature: func MultiWriter(writers ...Writer) Writer + hasQualifiedName("io", "MultiWriter") and + (inp.isResult() and outp.isParameter(_)) + or + // signature: func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader + hasQualifiedName("io", "NewSectionReader") and + (inp.isParameter(0) and outp.isResult()) + or + // signature: func Pipe() (*PipeReader, *PipeWriter) + hasQualifiedName("io", "Pipe") and + (inp.isResult(1) and outp.isResult(0)) + or + // signature: func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) + hasQualifiedName("io", "ReadAtLeast") and + (inp.isParameter(0) and outp.isParameter(1)) + or + // signature: func ReadFull(r Reader, buf []byte) (n int, err error) + hasQualifiedName("io", "ReadFull") and + (inp.isParameter(0) and outp.isParameter(1)) + or + // signature: func TeeReader(r Reader, w Writer) Reader + hasQualifiedName("io", "TeeReader") and + ( + inp.isParameter(0) and + (outp.isParameter(1) or outp.isResult()) + ) + or + // signature: func WriteString(w Writer, s string) (n int, err error) + hasQualifiedName("io", "WriteString") and + (inp.isParameter(1) 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 (*LimitedReader).Read(p []byte) (n int, err error) + this.hasQualifiedName("io", "LimitedReader", "Read") and + (inp.isReceiver() and outp.isParameter(0)) + or + // signature: func (*PipeReader).Read(data []byte) (n int, err error) + this.hasQualifiedName("io", "PipeReader", "Read") and + (inp.isReceiver() and outp.isParameter(0)) + or + // signature: func (*PipeWriter).Write(data []byte) (n int, err error) + this.hasQualifiedName("io", "PipeWriter", "Write") and + (inp.isParameter(0) and outp.isReceiver()) + or + // signature: func (*SectionReader).Read(p []byte) (n int, err error) + this.hasQualifiedName("io", "SectionReader", "Read") and + (inp.isReceiver() and outp.isParameter(0)) + or + // signature: func (*SectionReader).ReadAt(p []byte, off int64) (n int, err error) + this.hasQualifiedName("io", "SectionReader", "ReadAt") and + (inp.isReceiver() and outp.isParameter(0)) + or + // signature: func (Reader).Read(p []byte) (n int, err error) + this.implements("io", "Reader", "Read") and + (inp.isReceiver() and outp.isParameter(0)) + or + // signature: func (ReaderAt).ReadAt(p []byte, off int64) (n int, err error) + this.implements("io", "ReaderAt", "ReadAt") and + (inp.isReceiver() and outp.isParameter(0)) + or + // signature: func (ReaderFrom).ReadFrom(r Reader) (n int64, err error) + this.implements("io", "ReaderFrom", "ReadFrom") and + (inp.isParameter(0) and outp.isReceiver()) + or + // signature: func (Writer).Write(p []byte) (n int, err error) + this.implements("io", "Writer", "Write") and + (inp.isParameter(0) and outp.isReceiver()) + or + // signature: func (WriterAt).WriteAt(p []byte, off int64) (n int, err error) + this.implements("io", "WriterAt", "WriteAt") and + (inp.isParameter(0) and outp.isReceiver()) + or + // signature: func (StringWriter).WriteString(s string) (n int, err error) + this.implements("io", "StringWriter", "WriteString") and + (inp.isParameter(0) and outp.isReceiver()) + or + // signature: func (WriterTo).WriteTo(w Writer) (n int64, err error) + this.implements("io", "WriterTo", "WriteTo") and + (inp.isReceiver() and outp.isParameter(0)) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = inp and output = outp + } + } +} diff --git a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Io.go b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Io.go new file mode 100644 index 00000000000..e5bc3ca1cfd --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Io.go @@ -0,0 +1,305 @@ +// Code generated by https://github.com/gagliardetto/codebox. DO NOT EDIT. + +package main + +import "io" + +func TaintStepTest_IoCopy_B0I0O0(sourceCQL interface{}) interface{} { + fromReader656 := sourceCQL.(io.Reader) + var intoWriter414 io.Writer + io.Copy(intoWriter414, fromReader656) + return intoWriter414 +} + +func TaintStepTest_IoCopyBuffer_B0I0O0(sourceCQL interface{}) interface{} { + fromReader518 := sourceCQL.(io.Reader) + var intoWriter650 io.Writer + io.CopyBuffer(intoWriter650, fromReader518, nil) + return intoWriter650 +} + +func TaintStepTest_IoCopyN_B0I0O0(sourceCQL interface{}) interface{} { + fromReader784 := sourceCQL.(io.Reader) + var intoWriter957 io.Writer + io.CopyN(intoWriter957, fromReader784, 0) + return intoWriter957 +} + +func TaintStepTest_IoLimitReader_B0I0O0(sourceCQL interface{}) interface{} { + fromReader520 := sourceCQL.(io.Reader) + intoReader443 := io.LimitReader(fromReader520, 0) + return intoReader443 +} + +func TaintStepTest_IoMultiReader_B0I0O0(sourceCQL interface{}) interface{} { + fromReader127 := sourceCQL.(io.Reader) + intoReader483 := io.MultiReader(fromReader127) + return intoReader483 +} + +func TaintStepTest_IoMultiWriter_B0I0O0(sourceCQL interface{}) interface{} { + fromWriter989 := sourceCQL.(io.Writer) + var intoWriter982 io.Writer + intermediateCQL := io.MultiWriter(intoWriter982) + link(fromWriter989, intermediateCQL) + return intoWriter982 +} + +func TaintStepTest_IoNewSectionReader_B0I0O0(sourceCQL interface{}) interface{} { + fromReaderAt417 := sourceCQL.(io.ReaderAt) + intoSectionReader584 := io.NewSectionReader(fromReaderAt417, 0, 0) + return intoSectionReader584 +} + +func TaintStepTest_IoPipe_B0I0O0(sourceCQL interface{}) interface{} { + fromPipeWriter991 := sourceCQL.(*io.PipeWriter) + intoPipeReader881, intermediateCQL := io.Pipe() + link(fromPipeWriter991, intermediateCQL) + return intoPipeReader881 +} + +func TaintStepTest_IoReadAtLeast_B0I0O0(sourceCQL interface{}) interface{} { + fromReader186 := sourceCQL.(io.Reader) + var intoByte284 []byte + io.ReadAtLeast(fromReader186, intoByte284, 0) + return intoByte284 +} + +func TaintStepTest_IoReadFull_B0I0O0(sourceCQL interface{}) interface{} { + fromReader908 := sourceCQL.(io.Reader) + var intoByte137 []byte + io.ReadFull(fromReader908, intoByte137) + return intoByte137 +} + +func TaintStepTest_IoTeeReader_B0I0O0(sourceCQL interface{}) interface{} { + fromReader494 := sourceCQL.(io.Reader) + var intoWriter873 io.Writer + io.TeeReader(fromReader494, intoWriter873) + return intoWriter873 +} + +func TaintStepTest_IoTeeReader_B0I0O1(sourceCQL interface{}) interface{} { + fromReader599 := sourceCQL.(io.Reader) + intoReader409 := io.TeeReader(fromReader599, nil) + return intoReader409 +} + +func TaintStepTest_IoWriteString_B0I0O0(sourceCQL interface{}) interface{} { + fromString246 := sourceCQL.(string) + var intoWriter898 io.Writer + io.WriteString(intoWriter898, fromString246) + return intoWriter898 +} + +func TaintStepTest_IoLimitedReaderRead_B0I0O0(sourceCQL interface{}) interface{} { + fromLimitedReader598 := sourceCQL.(io.LimitedReader) + var intoByte631 []byte + fromLimitedReader598.Read(intoByte631) + return intoByte631 +} + +func TaintStepTest_IoPipeReaderRead_B0I0O0(sourceCQL interface{}) interface{} { + fromPipeReader165 := sourceCQL.(io.PipeReader) + var intoByte150 []byte + fromPipeReader165.Read(intoByte150) + return intoByte150 +} + +func TaintStepTest_IoPipeWriterWrite_B0I0O0(sourceCQL interface{}) interface{} { + fromByte340 := sourceCQL.([]byte) + var intoPipeWriter471 io.PipeWriter + intoPipeWriter471.Write(fromByte340) + return intoPipeWriter471 +} + +func TaintStepTest_IoSectionReaderRead_B0I0O0(sourceCQL interface{}) interface{} { + fromSectionReader290 := sourceCQL.(io.SectionReader) + var intoByte758 []byte + fromSectionReader290.Read(intoByte758) + return intoByte758 +} + +func TaintStepTest_IoSectionReaderReadAt_B0I0O0(sourceCQL interface{}) interface{} { + fromSectionReader396 := sourceCQL.(io.SectionReader) + var intoByte707 []byte + fromSectionReader396.ReadAt(intoByte707, 0) + return intoByte707 +} + +func TaintStepTest_IoReaderRead_B0I0O0(sourceCQL interface{}) interface{} { + fromReader912 := sourceCQL.(io.Reader) + var intoByte718 []byte + fromReader912.Read(intoByte718) + return intoByte718 +} + +func TaintStepTest_IoReaderAtReadAt_B0I0O0(sourceCQL interface{}) interface{} { + fromReaderAt972 := sourceCQL.(io.ReaderAt) + var intoByte633 []byte + fromReaderAt972.ReadAt(intoByte633, 0) + return intoByte633 +} + +func TaintStepTest_IoReaderFromReadFrom_B0I0O0(sourceCQL interface{}) interface{} { + fromReader316 := sourceCQL.(io.Reader) + var intoReaderFrom145 io.ReaderFrom + intoReaderFrom145.ReadFrom(fromReader316) + return intoReaderFrom145 +} + +func TaintStepTest_IoWriterWrite_B0I0O0(sourceCQL interface{}) interface{} { + fromByte817 := sourceCQL.([]byte) + var intoWriter474 io.Writer + intoWriter474.Write(fromByte817) + return intoWriter474 +} + +func TaintStepTest_IoWriterAtWriteAt_B0I0O0(sourceCQL interface{}) interface{} { + fromByte832 := sourceCQL.([]byte) + var intoWriterAt378 io.WriterAt + intoWriterAt378.WriteAt(fromByte832, 0) + return intoWriterAt378 +} + +func TaintStepTest_IoStringWriterWriteString_B0I0O0(sourceCQL interface{}) interface{} { + fromString541 := sourceCQL.(string) + var intoStringWriter139 io.StringWriter + intoStringWriter139.WriteString(fromString541) + return intoStringWriter139 +} + +func TaintStepTest_IoWriterToWriteTo_B0I0O0(sourceCQL interface{}) interface{} { + fromWriterTo814 := sourceCQL.(io.WriterTo) + var intoWriter768 io.Writer + fromWriterTo814.WriteTo(intoWriter768) + return intoWriter768 +} + +func RunAllTaints_Io() { + { + source := newSource(0) + out := TaintStepTest_IoCopy_B0I0O0(source) + sink(0, out) + } + { + source := newSource(1) + out := TaintStepTest_IoCopyBuffer_B0I0O0(source) + sink(1, out) + } + { + source := newSource(2) + out := TaintStepTest_IoCopyN_B0I0O0(source) + sink(2, out) + } + { + source := newSource(3) + out := TaintStepTest_IoLimitReader_B0I0O0(source) + sink(3, out) + } + { + source := newSource(4) + out := TaintStepTest_IoMultiReader_B0I0O0(source) + sink(4, out) + } + { + source := newSource(5) + out := TaintStepTest_IoMultiWriter_B0I0O0(source) + sink(5, out) + } + { + source := newSource(6) + out := TaintStepTest_IoNewSectionReader_B0I0O0(source) + sink(6, out) + } + { + source := newSource(7) + out := TaintStepTest_IoPipe_B0I0O0(source) + sink(7, out) + } + { + source := newSource(8) + out := TaintStepTest_IoReadAtLeast_B0I0O0(source) + sink(8, out) + } + { + source := newSource(9) + out := TaintStepTest_IoReadFull_B0I0O0(source) + sink(9, out) + } + { + source := newSource(10) + out := TaintStepTest_IoTeeReader_B0I0O0(source) + sink(10, out) + } + { + source := newSource(11) + out := TaintStepTest_IoTeeReader_B0I0O1(source) + sink(11, out) + } + { + source := newSource(12) + out := TaintStepTest_IoWriteString_B0I0O0(source) + sink(12, out) + } + { + source := newSource(13) + out := TaintStepTest_IoLimitedReaderRead_B0I0O0(source) + sink(13, out) + } + { + source := newSource(14) + out := TaintStepTest_IoPipeReaderRead_B0I0O0(source) + sink(14, out) + } + { + source := newSource(15) + out := TaintStepTest_IoPipeWriterWrite_B0I0O0(source) + sink(15, out) + } + { + source := newSource(16) + out := TaintStepTest_IoSectionReaderRead_B0I0O0(source) + sink(16, out) + } + { + source := newSource(17) + out := TaintStepTest_IoSectionReaderReadAt_B0I0O0(source) + sink(17, out) + } + { + source := newSource(18) + out := TaintStepTest_IoReaderRead_B0I0O0(source) + sink(18, out) + } + { + source := newSource(19) + out := TaintStepTest_IoReaderAtReadAt_B0I0O0(source) + sink(19, out) + } + { + source := newSource(20) + out := TaintStepTest_IoReaderFromReadFrom_B0I0O0(source) + sink(20, out) + } + { + source := newSource(21) + out := TaintStepTest_IoWriterWrite_B0I0O0(source) + sink(21, out) + } + { + source := newSource(22) + out := TaintStepTest_IoWriterAtWriteAt_B0I0O0(source) + sink(22, out) + } + { + source := newSource(23) + out := TaintStepTest_IoStringWriterWriteString_B0I0O0(source) + sink(23, out) + } + { + source := newSource(24) + out := TaintStepTest_IoWriterToWriteTo_B0I0O0(source) + sink(24, out) + } +}