[release-branch.go1.17] math/big: check buffer lengths in GobDecode

In Float.GobDecode and Rat.GobDecode, check buffer sizes before
indexing slices.

Updates #53871
Fixes #54094

Change-Id: I1b652c32c2bc7a0e8aa7620f7be9b2740c568b0a
Reviewed-on: https://go-review.googlesource.com/c/go/+/417774
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Tatiana Bradley <tatiana@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
(cherry picked from commit 055113ef364337607e3e72ed7d48df67fde6fc66)
Reviewed-on: https://go-review.googlesource.com/c/go/+/419814
Reviewed-by: Julie Qiu <julieqiu@google.com>
diff --git a/src/math/big/floatmarsh.go b/src/math/big/floatmarsh.go
index d1c1dab..990e085 100644
--- a/src/math/big/floatmarsh.go
+++ b/src/math/big/floatmarsh.go
@@ -8,6 +8,7 @@
 
 import (
 	"encoding/binary"
+	"errors"
 	"fmt"
 )
 
@@ -67,6 +68,9 @@
 		*z = Float{}
 		return nil
 	}
+	if len(buf) < 6 {
+		return errors.New("Float.GobDecode: buffer too small")
+	}
 
 	if buf[0] != floatGobVersion {
 		return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0])
@@ -83,6 +87,9 @@
 	z.prec = binary.BigEndian.Uint32(buf[2:])
 
 	if z.form == finite {
+		if len(buf) < 10 {
+			return errors.New("Float.GobDecode: buffer too small for finite form float")
+		}
 		z.exp = int32(binary.BigEndian.Uint32(buf[6:]))
 		z.mant = z.mant.setBytes(buf[10:])
 	}
diff --git a/src/math/big/floatmarsh_test.go b/src/math/big/floatmarsh_test.go
index c056d78..401f45a 100644
--- a/src/math/big/floatmarsh_test.go
+++ b/src/math/big/floatmarsh_test.go
@@ -137,3 +137,15 @@
 		}
 	}
 }
+
+func TestFloatGobDecodeShortBuffer(t *testing.T) {
+	for _, tc := range [][]byte{
+		[]byte{0x1, 0x0, 0x0, 0x0},
+		[]byte{0x1, 0xfa, 0x0, 0x0, 0x0, 0x0},
+	} {
+		err := NewFloat(0).GobDecode(tc)
+		if err == nil {
+			t.Error("expected GobDecode to return error for malformed input")
+		}
+	}
+}
diff --git a/src/math/big/ratmarsh.go b/src/math/big/ratmarsh.go
index fbc7b60..56102e8 100644
--- a/src/math/big/ratmarsh.go
+++ b/src/math/big/ratmarsh.go
@@ -45,12 +45,18 @@
 		*z = Rat{}
 		return nil
 	}
+	if len(buf) < 5 {
+		return errors.New("Rat.GobDecode: buffer too small")
+	}
 	b := buf[0]
 	if b>>1 != ratGobVersion {
 		return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
 	}
 	const j = 1 + 4
 	i := j + binary.BigEndian.Uint32(buf[j-4:j])
+	if len(buf) < int(i) {
+		return errors.New("Rat.GobDecode: buffer too small")
+	}
 	z.a.neg = b&1 != 0
 	z.a.abs = z.a.abs.setBytes(buf[j:i])
 	z.b.abs = z.b.abs.setBytes(buf[i:])
diff --git a/src/math/big/ratmarsh_test.go b/src/math/big/ratmarsh_test.go
index 351d109..55a9878 100644
--- a/src/math/big/ratmarsh_test.go
+++ b/src/math/big/ratmarsh_test.go
@@ -123,3 +123,15 @@
 		}
 	}
 }
+
+func TestRatGobDecodeShortBuffer(t *testing.T) {
+	for _, tc := range [][]byte{
+		[]byte{0x2},
+		[]byte{0x2, 0x0, 0x0, 0x0, 0xff},
+	} {
+		err := NewRat(1, 2).GobDecode(tc)
+		if err == nil {
+			t.Error("expected GobDecode to return error for malformed input")
+		}
+	}
+}