Skip to content

Commit

Permalink
Merge pull request #1376 from ozfive/master
Browse files Browse the repository at this point in the history
This commit fixes a potential denial of service vulnerability in logrus.Writer() that could be triggered by logging text longer than 64kb without newlines.
  • Loading branch information
sirupsen authored May 15, 2023
2 parents e59b167 + 105e63f commit 6acd903
Showing 1 changed file with 33 additions and 1 deletion.
34 changes: 33 additions & 1 deletion writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"io"
"runtime"
"strings"
)

// Writer at INFO level. See WriterLevel for details.
Expand All @@ -20,15 +21,18 @@ func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
return NewEntry(logger).WriterLevel(level)
}

// Writer returns an io.Writer that writes to the logger at the info log level
func (entry *Entry) Writer() *io.PipeWriter {
return entry.WriterLevel(InfoLevel)
}

// WriterLevel returns an io.Writer that writes to the logger at the given log level
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
reader, writer := io.Pipe()

var printFunc func(args ...interface{})

// Determine which log function to use based on the specified log level
switch level {
case TraceLevel:
printFunc = entry.Trace
Expand All @@ -48,23 +52,51 @@ func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
printFunc = entry.Print
}

// Start a new goroutine to scan the input and write it to the logger using the specified print function.
// It splits the input into chunks of up to 64KB to avoid buffer overflows.
go entry.writerScanner(reader, printFunc)

// Set a finalizer function to close the writer when it is garbage collected
runtime.SetFinalizer(writer, writerFinalizer)

return writer
}

// writerScanner scans the input from the reader and writes it to the logger
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
scanner := bufio.NewScanner(reader)

// Set the buffer size to the maximum token size to avoid buffer overflows
scanner.Buffer(make([]byte, bufio.MaxScanTokenSize), bufio.MaxScanTokenSize)

// Define a split function to split the input into chunks of up to 64KB
chunkSize := 64 * 1024 // 64KB
splitFunc := func(data []byte, atEOF bool) (int, []byte, error) {
if len(data) > chunkSize {
return chunkSize, data[:chunkSize], nil
}

return len(data), data, nil
}

//Use the custom split function to split the input
scanner.Split(splitFunc)

// Scan the input and write it to the logger using the specified print function
for scanner.Scan() {
printFunc(scanner.Text())
printFunc(strings.TrimRight(scanner.Text(), "\r\n"))
}

// If there was an error while scanning the input, log an error
if err := scanner.Err(); err != nil {
entry.Errorf("Error while reading from Writer: %s", err)
}

// Close the reader when we are done
reader.Close()
}

// WriterFinalizer is a finalizer function that closes then given writer when it is garbage collected
func writerFinalizer(writer *io.PipeWriter) {
writer.Close()
}

0 comments on commit 6acd903

Please sign in to comment.