fix(bsr): check nanosecond range during decoding (#3496)
This commit is contained in:
1 parent
f59b6364f2
commit
dcdb257b93
3 files changed
+70
No files matched your search
@@ -41,4 +41,7 @@ var (
|
||||
|
||||
// ErrChecksum indicates that a checksum did not match.
|
||||
ErrChecksum = errors.New("computed checksum did NOT match")
|
||||
|
||||
// ErrTimestampDecode indicates an error decoding a timestamp
|
||||
ErrTimestampDecode = errors.New("error decoding timestamp")
|
||||
)
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
const (
|
||||
secondSize = 8
|
||||
nanosecondSize = 4
|
||||
// Values over 999999999 are 1 second and over
|
||||
nanosecondLimit = 999999999
|
||||
|
||||
timestampSize = secondSize + nanosecondSize
|
||||
)
|
||||
@@ -52,6 +54,9 @@ func decodeTimestamp(data []byte) (*Timestamp, error) {
|
||||
|
||||
seconds, data = binary.BigEndian.Uint64(data[:secondSize]), data[secondSize:]
|
||||
nanoseconds, data = binary.BigEndian.Uint32(data[:nanosecondSize]), data[nanosecondSize:]
|
||||
if nanoseconds > nanosecondLimit {
|
||||
return nil, fmt.Errorf("%s: nanosecond value of %d exceeds the max nanosecond value of %d: %w", op, nanoseconds, nanosecondLimit, ErrTimestampDecode)
|
||||
}
|
||||
if len(data) != 0 {
|
||||
return nil, fmt.Errorf("%s: extra data", op)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package bsr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_DecodeTimestamp(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
nanos uint32
|
||||
wantNanos int
|
||||
wantErr bool
|
||||
wantErrContains string
|
||||
}{
|
||||
{
|
||||
name: "valid case 1",
|
||||
nanos: uint32(999999999),
|
||||
wantNanos: 999999999,
|
||||
},
|
||||
{
|
||||
name: "valid case 2",
|
||||
nanos: uint32(5),
|
||||
wantNanos: 5,
|
||||
},
|
||||
{
|
||||
name: "nanosecond overflow case 1",
|
||||
nanos: uint32(1000000000),
|
||||
wantErr: true,
|
||||
wantErrContains: "bsr.decodeTimestamp: nanosecond value of 1000000000 exceeds the max nanosecond value of 999999999: error decoding timestamp",
|
||||
},
|
||||
{
|
||||
name: "nanosecond overflow case 2",
|
||||
nanos: uint32(2000000000),
|
||||
wantErr: true,
|
||||
wantErrContains: "bsr.decodeTimestamp: nanosecond value of 2000000000 exceeds the max nanosecond value of 999999999: error decoding timestamp",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
data := make([]byte, timestampSize)
|
||||
seconds := uint64(0)
|
||||
binary.BigEndian.PutUint64(data[:secondSize], seconds)
|
||||
binary.BigEndian.PutUint32(data[secondSize:], tc.nanos)
|
||||
got, err := decodeTimestamp(data)
|
||||
if tc.wantErr {
|
||||
require.Error(t, err)
|
||||
assert.EqualError(t, err, tc.wantErrContains)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.wantNanos, got.AsTime().Nanosecond())
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user