Skip to content

Commit aafad20

Browse files
committed
encoding/binary: limit bytes read by Uvarint to <= 10
Limits the number of bytes that can be consumed by Uvarint to MaxVarintLen64 (10) to avoid wasted computations. With this change, if Uvarint reads more than MaxVarintLen64 bytes, it'll return the erroring byte count of n=-(MaxVarintLen64+1) which is -11, as per the function signature. Updated some tests to reflect the new change in expectations of n when the number of bytes to be read exceeds the limits.. Fixes #41185 Change-Id: Ie346457b1ddb0214b60c72e81128e24d604d083d Reviewed-on: https://go-review.googlesource.com/c/go/+/299531 Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org> Trust: Emmanuel Odeke <emmanuel@orijtech.com>
1 parent 125eca0 commit aafad20

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

src/encoding/binary/varint.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,13 @@ func Uvarint(buf []byte) (uint64, int) {
6161
var x uint64
6262
var s uint
6363
for i, b := range buf {
64+
if i == MaxVarintLen64 {
65+
// Catch byte reads past MaxVarintLen64.
66+
// See issue https://golang.org/issues/41185
67+
return 0, -(i + 1) // overflow
68+
}
6469
if b < 0x80 {
65-
if i >= MaxVarintLen64 || i == MaxVarintLen64-1 && b > 1 {
70+
if i == MaxVarintLen64-1 && b > 1 {
6671
return 0, -(i + 1) // overflow
6772
}
6873
return x | uint64(b)<<s, i + 1

src/encoding/binary/varint_test.go

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package binary
77
import (
88
"bytes"
99
"io"
10+
"math"
1011
"testing"
1112
)
1213

@@ -121,10 +122,66 @@ func TestBufferTooSmall(t *testing.T) {
121122
}
122123
}
123124

125+
// Ensure that we catch overflows of bytes going past MaxVarintLen64.
126+
// See issue https://golang.org/issues/41185
127+
func TestBufferTooBigWithOverflow(t *testing.T) {
128+
tests := []struct {
129+
in []byte
130+
name string
131+
wantN int
132+
wantValue uint64
133+
}{
134+
{
135+
name: "invalid: 1000 bytes",
136+
in: func() []byte {
137+
b := make([]byte, 1000)
138+
for i := range b {
139+
b[i] = 0xff
140+
}
141+
b[999] = 0
142+
return b
143+
}(),
144+
wantN: -11,
145+
wantValue: 0,
146+
},
147+
{
148+
name: "valid: math.MaxUint64-40",
149+
in: []byte{0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01},
150+
wantValue: math.MaxUint64 - 40,
151+
wantN: 10,
152+
},
153+
{
154+
name: "invalid: with more than MaxVarintLen64 bytes",
155+
in: []byte{0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01},
156+
wantN: -11,
157+
wantValue: 0,
158+
},
159+
{
160+
name: "invalid: 10th byte",
161+
in: []byte{0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},
162+
wantN: -10,
163+
wantValue: 0,
164+
},
165+
}
166+
167+
for _, tt := range tests {
168+
tt := tt
169+
t.Run(tt.name, func(t *testing.T) {
170+
value, n := Uvarint(tt.in)
171+
if g, w := n, tt.wantN; g != w {
172+
t.Errorf("bytes returned=%d, want=%d", g, w)
173+
}
174+
if g, w := value, tt.wantValue; g != w {
175+
t.Errorf("value=%d, want=%d", g, w)
176+
}
177+
})
178+
}
179+
}
180+
124181
func testOverflow(t *testing.T, buf []byte, x0 uint64, n0 int, err0 error) {
125182
x, n := Uvarint(buf)
126183
if x != 0 || n != n0 {
127-
t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, %d", buf, x, n, n0)
184+
t.Errorf("Uvarint(% X): got x = %d, n = %d; want 0, %d", buf, x, n, n0)
128185
}
129186

130187
r := bytes.NewReader(buf)
@@ -140,8 +197,8 @@ func testOverflow(t *testing.T, buf []byte, x0 uint64, n0 int, err0 error) {
140197

141198
func TestOverflow(t *testing.T) {
142199
testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x2}, 0, -10, overflow)
143-
testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1, 0, 0}, 0, -13, overflow)
144-
testOverflow(t, []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 1<<64-1, 0, overflow) // 11 bytes, should overflow
200+
testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1, 0, 0}, 0, -11, overflow)
201+
testOverflow(t, []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 1<<64-1, -11, overflow) // 11 bytes, should overflow
145202
}
146203

147204
func TestNonCanonicalZero(t *testing.T) {

0 commit comments

Comments
 (0)