Skip to content

Commit

Permalink
Fix panic on unpack nil or smaller input size (#161)
Browse files Browse the repository at this point in the history
* fix decode with nil or zero/wrong length data

* check input length to avoid panic because of slice bounds out of range
  • Loading branch information
alovak authored Feb 9, 2022
1 parent f72989c commit 07d52aa
Show file tree
Hide file tree
Showing 13 changed files with 81 additions and 4 deletions.
7 changes: 6 additions & 1 deletion encoding/ascii.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package encoding

import "fmt"
import (
"fmt"
)

var ASCII Encoder = &asciiEncoder{}

Expand All @@ -20,6 +22,9 @@ func (e asciiEncoder) Encode(data []byte) ([]byte, error) {

func (e asciiEncoder) Decode(data []byte, length int) ([]byte, int, error) {
// read only 'length' bytes (1 byte - 1 ASCII character)
if len(data) < length {
return nil, 0, fmt.Errorf("not enough data to decode. expected len %d, got %d", length, len(data))
}
data = data[:length]
var out []byte
for _, r := range data {
Expand Down
8 changes: 8 additions & 0 deletions encoding/ascii_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ func TestASCII(t *testing.T) {

_, _, err = enc.Decode([]byte("hello, 世界!"), 10)
require.Error(t, err)

_, _, err = enc.Decode([]byte("hello"), 6)
require.Error(t, err)
require.EqualError(t, err, "not enough data to decode. expected len 6, got 5")

_, _, err = enc.Decode(nil, 6)
require.Error(t, err)
require.EqualError(t, err, "not enough data to decode. expected len 6, got 0")
})

t.Run("Encode", func(t *testing.T) {
Expand Down
6 changes: 6 additions & 0 deletions encoding/bcd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package encoding

import (
"fmt"

"github.com/yerden/go-util/bcd"
)

Expand Down Expand Up @@ -33,6 +35,10 @@ func (e *bcdEncoder) Decode(src []byte, length int) ([]byte, int, error) {
// how many bytes we will read
read := bcd.EncodedLen(decodedLen)

if len(src) < read {
return nil, 0, fmt.Errorf("not enough data to decode. expected len %d, got %d", read, len(src))
}

dec := bcd.NewDecoder(bcd.Standard)
dst := make([]byte, decodedLen)
_, err := dec.Decode(dst, src[:read])
Expand Down
8 changes: 8 additions & 0 deletions encoding/bcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ func TestBCD(t *testing.T) {
require.NoError(t, err)
require.Equal(t, []byte("2143"), res)
require.Equal(t, 2, read)

_, _, err = BCD.Decode([]byte{0x21, 0x43}, 6)
require.Error(t, err)
require.EqualError(t, err, "not enough data to decode. expected len 3, got 2")

_, _, err = BCD.Decode(nil, 6)
require.Error(t, err)
require.EqualError(t, err, "not enough data to decode. expected len 3, got 0")
})

t.Run("Encode", func(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions encoding/ebcdic.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package encoding

import "fmt"

//Encoding map taken from
//http://www.ibm.com/support/knowledgecenter/SSZJPZ_11.3.0/com.ibm.swg.im.iis.ds.parjob.adref.doc/topics/r_deeadvrf_EBCDIC_to_ASCII.html

Expand Down Expand Up @@ -86,6 +88,9 @@ func (e *ebcdicEncoder) Encode(src []byte) ([]byte, error) {
}

func (e *ebcdicEncoder) Decode(src []byte, length int) ([]byte, int, error) {
if len(src) < length {
return nil, 0, fmt.Errorf("not enough data to decode. expected len %d, got %d", length, len(src))
}
src = src[:length]
var dst []byte
for _, v := range src {
Expand Down
8 changes: 8 additions & 0 deletions encoding/ebcdic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ func TestEBCDIC(t *testing.T) {
require.Equal(t, []byte{0x12, 0x94}, res)
require.Equal(t, 2, read)

_, _, err = EBCDIC.Decode([]byte{0x12, 0x34}, 3)
require.Error(t, err)
require.EqualError(t, err, "not enough data to decode. expected len 3, got 2")

_, _, err = EBCDIC.Decode(nil, 6)
require.Error(t, err)
require.EqualError(t, err, "not enough data to decode. expected len 6, got 0")

})

t.Run("Encode", func(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions encoding/hex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ func TestHexToASCIIEncoder(t *testing.T) {
require.Equal(t, 6, read)
require.Equal(t, []byte{0xAA, 0xBB, 0xCC}, got)

_, _, err = enc.Decode(nil, 3)
require.Error(t, err)
require.EqualError(t, err, "not enough data to read")

got, err = enc.Encode([]byte{0xAA, 0xBB, 0xCC})
require.NoError(t, err)
require.Equal(t, []byte("AABBCC"), got)
Expand Down
7 changes: 7 additions & 0 deletions encoding/lbcd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package encoding

import (
"fmt"

"github.com/yerden/go-util/bcd"
)

Expand Down Expand Up @@ -33,6 +35,11 @@ func (e *lBCDEncoder) Decode(src []byte, length int) ([]byte, int, error) {

dec := bcd.NewDecoder(bcd.Standard)
dst := make([]byte, decodedLen)

if len(src) < read {
return nil, 0, fmt.Errorf("not enough data to decode. expected len %d, got %d", read, len(src))
}

_, err := dec.Decode(dst, src)
if err != nil {
return nil, 0, err
Expand Down
8 changes: 8 additions & 0 deletions encoding/lbcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ func TestLBCD(t *testing.T) {
require.NoError(t, err)
require.Equal(t, []byte("123"), res)
require.Equal(t, 2, read)

_, _, err = LBCD.Decode([]byte{0x12, 0x30}, 5)
require.Error(t, err)
require.EqualError(t, err, "not enough data to decode. expected len 3, got 2")

_, _, err = LBCD.Decode(nil, 5)
require.Error(t, err)
require.EqualError(t, err, "not enough data to decode. expected len 3, got 0")
})

t.Run("Encode", func(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion field/composite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ func TestCompositePacking(t *testing.T) {
read, err := composite.Unpack([]byte("ABCD123"))
require.Equal(t, 0, read)
require.Error(t, err)
require.EqualError(t, err, "data length: 4 does not match aggregate data read from decoded subfields: 7")
require.EqualError(t, err, "failed to unpack subfield 3: failed to decode content: not enough data to decode. expected len 3, got 0")
})

t.Run("Unpack correctly deserialises bytes to the data struct", func(t *testing.T) {
Expand Down
18 changes: 18 additions & 0 deletions message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,24 @@ func TestPackUnpack(t *testing.T) {
assert.Equal(t, "000000000501", data.F55.F9F02.Value)
assert.Equal(t, "Another test text", data.F120.Value)
})

t.Run("Unpack nil", func(t *testing.T) {
message := NewMessage(spec)

err := message.Unpack(nil)

require.Error(t, err)
})

t.Run("Unpack short mti", func(t *testing.T) {
message := NewMessage(spec)

rawMsg := []byte{0x30, 0x31}

err := message.Unpack([]byte(rawMsg))

require.Error(t, err)
})
}

func TestMessageJSON(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion prefix/ascii.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (p *asciiVarPrefixer) EncodeLength(maxLen, dataLen int) ([]byte, error) {

func (p *asciiVarPrefixer) DecodeLength(maxLen int, data []byte) (int, int, error) {
if len(data) < p.Digits {
return 0, 0, fmt.Errorf("not enought data length: %d to read: %d byte digits", len(data), p.Digits)
return 0, 0, fmt.Errorf("not enough data length: %d to read: %d byte digits", len(data), p.Digits)
}

dataLen, err := strconv.Atoi(string(data[:p.Digits]))
Expand Down
2 changes: 1 addition & 1 deletion prefix/ascii_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestAsciiVarPrefixer_DecodeLengthMaxLengthValidation(t *testing.T) {

_, _, err := pref.DecodeLength(20, []byte("22"))

require.Contains(t, err.Error(), "not enought data length: 2 to read: 3 byte digits")
require.Contains(t, err.Error(), "not enough data length: 2 to read: 3 byte digits")
}

func TestAsciiVarPrefixer_LHelpers(t *testing.T) {
Expand Down

0 comments on commit 07d52aa

Please sign in to comment.