Skip to content

Commit

Permalink
chore: Enable G110 rule for gosec (influxdata#13044)
Browse files Browse the repository at this point in the history
Co-authored-by: Pawel Zak <Pawel Zak>
  • Loading branch information
zak-pawel authored Apr 14, 2023
1 parent 596ecc4 commit ba16eeb
Show file tree
Hide file tree
Showing 14 changed files with 120 additions and 36 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ linters-settings:
- G107
- G108
- G109
- G110
- G111
- G112
- G114
Expand Down
32 changes: 23 additions & 9 deletions internal/content_coding.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import (
"compress/gzip"
"compress/zlib"
"errors"
"fmt"
"io"
)

const DefaultMaxDecompressionSize = 500 * 1024 * 1024 //500MB

// NewStreamContentDecoder returns a reader that will decode the stream
// according to the encoding type.
func NewStreamContentDecoder(encoding string, r io.Reader) (io.Reader, error) {
Expand Down Expand Up @@ -92,11 +95,11 @@ func (a *AutoDecoder) SetEncoding(encoding string) {
a.encoding = encoding
}

func (a *AutoDecoder) Decode(data []byte) ([]byte, error) {
func (a *AutoDecoder) Decode(data []byte, maxDecompressionSize int64) ([]byte, error) {
if a.encoding == "gzip" {
return a.gzip.Decode(data)
return a.gzip.Decode(data, maxDecompressionSize)
}
return a.identity.Decode(data)
return a.identity.Decode(data, maxDecompressionSize)
}

func NewAutoContentDecoder() *AutoDecoder {
Expand Down Expand Up @@ -199,7 +202,7 @@ func (*IdentityEncoder) Encode(data []byte) ([]byte, error) {
// ContentDecoder removes a wrapper encoding from byte buffers.
type ContentDecoder interface {
SetEncoding(string)
Decode([]byte) ([]byte, error)
Decode([]byte, int64) ([]byte, error)
}

// GzipDecoder decompresses buffers with gzip compression.
Expand All @@ -217,17 +220,20 @@ func NewGzipDecoder() *GzipDecoder {

func (*GzipDecoder) SetEncoding(string) {}

func (d *GzipDecoder) Decode(data []byte) ([]byte, error) {
func (d *GzipDecoder) Decode(data []byte, maxDecompressionSize int64) ([]byte, error) {
err := d.reader.Reset(bytes.NewBuffer(data))
if err != nil {
return nil, err
}
d.buf.Reset()

_, err = d.buf.ReadFrom(d.reader)
n, err := io.CopyN(d.buf, d.reader, maxDecompressionSize)
if err != nil && !errors.Is(err, io.EOF) {
return nil, err
} else if n == maxDecompressionSize {
return nil, fmt.Errorf("size of decoded data exceeds allowed size %d", maxDecompressionSize)
}

err = d.reader.Close()
if err != nil {
return nil, err
Expand All @@ -247,18 +253,22 @@ func NewZlibDecoder() *ZlibDecoder {

func (*ZlibDecoder) SetEncoding(string) {}

func (d *ZlibDecoder) Decode(data []byte) ([]byte, error) {
func (d *ZlibDecoder) Decode(data []byte, maxDecompressionSize int64) ([]byte, error) {
d.buf.Reset()

b := bytes.NewBuffer(data)
r, err := zlib.NewReader(b)
if err != nil {
return nil, err
}
_, err = io.Copy(d.buf, r)

n, err := io.CopyN(d.buf, r, maxDecompressionSize)
if err != nil && !errors.Is(err, io.EOF) {
return nil, err
} else if n == maxDecompressionSize {
return nil, fmt.Errorf("size of decoded data exceeds allowed size %d", maxDecompressionSize)
}

err = r.Close()
if err != nil {
return nil, err
Expand All @@ -275,6 +285,10 @@ func NewIdentityDecoder() *IdentityDecoder {

func (*IdentityDecoder) SetEncoding(string) {}

func (*IdentityDecoder) Decode(data []byte) ([]byte, error) {
func (*IdentityDecoder) Decode(data []byte, maxDecompressionSize int64) ([]byte, error) {
size := int64(len(data))
if size > maxDecompressionSize {
return nil, fmt.Errorf("size of decoded data: %d exceeds allowed size %d", size, maxDecompressionSize)
}
return data, nil
}
23 changes: 18 additions & 5 deletions internal/content_coding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ import (
"github.com/stretchr/testify/require"
)

const maxDecompressionSize = 1024

func TestGzipEncodeDecode(t *testing.T) {
enc := NewGzipEncoder()
dec := NewGzipDecoder()

payload, err := enc.Encode([]byte("howdy"))
require.NoError(t, err)

actual, err := dec.Decode(payload)
actual, err := dec.Decode(payload, maxDecompressionSize)
require.NoError(t, err)

require.Equal(t, "howdy", string(actual))
Expand All @@ -28,15 +30,15 @@ func TestGzipReuse(t *testing.T) {
payload, err := enc.Encode([]byte("howdy"))
require.NoError(t, err)

actual, err := dec.Decode(payload)
actual, err := dec.Decode(payload, maxDecompressionSize)
require.NoError(t, err)

require.Equal(t, "howdy", string(actual))

payload, err = enc.Encode([]byte("doody"))
require.NoError(t, err)

actual, err = dec.Decode(payload)
actual, err = dec.Decode(payload, maxDecompressionSize)
require.NoError(t, err)

require.Equal(t, "doody", string(actual))
Expand All @@ -49,20 +51,31 @@ func TestZlibEncodeDecode(t *testing.T) {
payload, err := enc.Encode([]byte("howdy"))
require.NoError(t, err)

actual, err := dec.Decode(payload)
actual, err := dec.Decode(payload, maxDecompressionSize)
require.NoError(t, err)

require.Equal(t, "howdy", string(actual))
}

func TestZlibEncodeDecodeWithTooLargeMessage(t *testing.T) {
enc := NewZlibEncoder()
dec := NewZlibDecoder()

payload, err := enc.Encode([]byte("howdy"))
require.NoError(t, err)

_, err = dec.Decode(payload, 3)
require.ErrorContains(t, err, "size of decoded data exceeds allowed size 3")
}

func TestIdentityEncodeDecode(t *testing.T) {
enc := NewIdentityEncoder()
dec := NewIdentityDecoder()

payload, err := enc.Encode([]byte("howdy"))
require.NoError(t, err)

actual, err := dec.Decode(payload)
actual, err := dec.Decode(payload, maxDecompressionSize)
require.NoError(t, err)

require.Equal(t, "howdy", string(actual))
Expand Down
5 changes: 5 additions & 0 deletions plugins/inputs/amqp_consumer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## - Use "auto" determine the encoding using the ContentEncoding header
# content_encoding = "identity"

## Maximum size of decoded message.
## Acceptable units are B, KiB, KB, MiB, MB...
## Without quotes and units, interpreted as size in bytes.
# max_decompression_size = "500MB"

## Data format to consume.
## Each data format has its own unique set of configuration options, read
## more about them here:
Expand Down
16 changes: 11 additions & 5 deletions plugins/inputs/amqp_consumer/amqp_consumer.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
amqp "github.com/rabbitmq/amqp091-go"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/common/tls"
"github.com/influxdata/telegraf/plugins/inputs"
Expand Down Expand Up @@ -55,8 +56,9 @@ type AMQPConsumer struct {
AuthMethod string
tls.ClientConfig

ContentEncoding string `toml:"content_encoding"`
Log telegraf.Logger
ContentEncoding string `toml:"content_encoding"`
MaxDecompressionSize config.Size `toml:"max_decompression_size"`
Log telegraf.Logger

deliveries map[telegraf.TrackingID]amqp.Delivery

Expand Down Expand Up @@ -113,6 +115,10 @@ func (a *AMQPConsumer) Init() error {
a.MaxUndeliveredMessages = 1000
}

if a.MaxDecompressionSize <= 0 {
a.MaxDecompressionSize = internal.DefaultMaxDecompressionSize
}

return nil
}

Expand Down Expand Up @@ -144,11 +150,11 @@ func (a *AMQPConsumer) createConfig() (*amqp.Config, error) {
}
}

config := amqp.Config{
amqpConfig := amqp.Config{
TLSClientConfig: tlsCfg,
SASL: auth, // if nil, it will be PLAIN
}
return &config, nil
return &amqpConfig, nil
}

// Start satisfies the telegraf.ServiceInput interface
Expand Down Expand Up @@ -412,7 +418,7 @@ func (a *AMQPConsumer) onMessage(acc telegraf.TrackingAccumulator, d amqp.Delive
}

a.decoder.SetEncoding(d.ContentEncoding)
body, err := a.decoder.Decode(d.Body)
body, err := a.decoder.Decode(d.Body, int64(a.MaxDecompressionSize))
if err != nil {
onError()
return err
Expand Down
1 change: 1 addition & 0 deletions plugins/inputs/amqp_consumer/amqp_consumer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestAutoEncoding(t *testing.T) {
a.deliveries = make(map[telegraf.TrackingID]amqp091.Delivery)
a.parser = parser
a.decoder, err = internal.NewContentDecoder("auto")
a.MaxDecompressionSize = internal.DefaultMaxDecompressionSize
require.NoError(t, err)

acc := &testutil.Accumulator{}
Expand Down
5 changes: 5 additions & 0 deletions plugins/inputs/amqp_consumer/sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
## - Use "auto" determine the encoding using the ContentEncoding header
# content_encoding = "identity"

## Maximum size of decoded message.
## Acceptable units are B, KiB, KB, MiB, MB...
## Without quotes and units, interpreted as size in bytes.
# max_decompression_size = "500MB"

## Data format to consume.
## Each data format has its own unique set of configuration options, read
## more about them here:
Expand Down
5 changes: 5 additions & 0 deletions plugins/inputs/socket_listener/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## "identity" to apply no encoding.
# content_encoding = "identity"

## Maximum size of decoded packet.
## Acceptable units are B, KiB, KB, MiB, MB...
## Without quotes and units, interpreted as size in bytes.
# max_decompression_size = "500MB"

## Message splitting strategy and corresponding settings for stream sockets
## (tcp, tcp4, tcp6, unix or unixpacket). The setting is ignored for packet
## listeners such as udp.
Expand Down
13 changes: 7 additions & 6 deletions plugins/inputs/socket_listener/packet_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import (
)

type packetListener struct {
Encoding string
SocketMode string
ReadBufferSize int
Parser telegraf.Parser
Log telegraf.Logger
Encoding string
MaxDecompressionSize int64
SocketMode string
ReadBufferSize int
Parser telegraf.Parser
Log telegraf.Logger

conn net.PacketConn
decoder internal.ContentDecoder
Expand All @@ -36,7 +37,7 @@ func (l *packetListener) listen(acc telegraf.Accumulator) {
break
}

body, err := l.decoder.Decode(buf[:n])
body, err := l.decoder.Decode(buf[:n], l.MaxDecompressionSize)
if err != nil {
acc.AddError(fmt.Errorf("unable to decode incoming packet: %w", err))
}
Expand Down
5 changes: 5 additions & 0 deletions plugins/inputs/socket_listener/sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
## "identity" to apply no encoding.
# content_encoding = "identity"

## Maximum size of decoded packet.
## Acceptable units are B, KiB, KB, MiB, MB...
## Without quotes and units, interpreted as size in bytes.
# max_decompression_size = "500MB"

## Message splitting strategy and corresponding settings for stream sockets
## (tcp, tcp4, tcp6, unix or unixpacket). The setting is ignored for packet
## listeners such as udp.
Expand Down
21 changes: 15 additions & 6 deletions plugins/inputs/socket_listener/socket_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/internal"
tlsint "github.com/influxdata/telegraf/plugins/common/tls"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/influxdata/telegraf/plugins/parsers"
Expand Down Expand Up @@ -45,6 +46,7 @@ type SocketListener struct {
KeepAlivePeriod *config.Duration `toml:"keep_alive_period"`
SocketMode string `toml:"socket_mode"`
ContentEncoding string `toml:"content_encoding"`
MaxDecompressionSize config.Size `toml:"max_decompression_size"`
SplittingStrategy string `toml:"splitting_strategy"`
SplittingDelimiter string `toml:"splitting_delimiter"`
SplittingLength int `toml:"splitting_length"`
Expand Down Expand Up @@ -159,6 +161,10 @@ func (sl *SocketListener) Start(acc telegraf.Accumulator) error {
return fmt.Errorf("parsing address failed: %w", err)
}

if sl.MaxDecompressionSize <= 0 {
sl.MaxDecompressionSize = internal.DefaultMaxDecompressionSize
}

switch u.Scheme {
case "tcp", "tcp4", "tcp6":
ssl := &streamListener{
Expand Down Expand Up @@ -195,26 +201,29 @@ func (sl *SocketListener) Start(acc telegraf.Accumulator) error {

case "udp", "udp4", "udp6":
psl := &packetListener{
Encoding: sl.ContentEncoding,
Parser: sl.parser,
Encoding: sl.ContentEncoding,
MaxDecompressionSize: int64(sl.MaxDecompressionSize),
Parser: sl.parser,
}
if err := psl.setupUDP(u, ifname, int(sl.ReadBufferSize)); err != nil {
return err
}
sl.listener = psl
case "ip", "ip4", "ip6":
psl := &packetListener{
Encoding: sl.ContentEncoding,
Parser: sl.parser,
Encoding: sl.ContentEncoding,
MaxDecompressionSize: int64(sl.MaxDecompressionSize),
Parser: sl.parser,
}
if err := psl.setupIP(u); err != nil {
return err
}
sl.listener = psl
case "unixgram":
psl := &packetListener{
Encoding: sl.ContentEncoding,
Parser: sl.parser,
Encoding: sl.ContentEncoding,
MaxDecompressionSize: int64(sl.MaxDecompressionSize),
Parser: sl.parser,
}
if err := psl.setupUnixgram(u, sl.SocketMode); err != nil {
return err
Expand Down
Loading

0 comments on commit ba16eeb

Please sign in to comment.