fix: math: fix Uint.Unmarshal's lack of negative value checking (#11996)

This change adds a negative value check to Uint.Unmarshal,
which coincidentally is fixed by refactoring for code reuse.
While here, added tests to ensure we don't regress.

Fixes #11995
This commit is contained in:
Emmanuel T Odeke 2022-05-19 23:28:06 +03:00 committed by GitHub
parent 89c727cb78
commit 54d764b9a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 7 deletions

View File

@ -190,11 +190,8 @@ func (u *Uint) Unmarshal(data []byte) error {
return err return err
} }
if u.i.BitLen() > MaxBitLen { // Finally check for overflow.
return fmt.Errorf("integer out of range; got: %d, max: %d", u.i.BitLen(), MaxBitLen) return UintOverflow(u.i)
}
return nil
} }
// Size implements the gogo proto custom type interface. // Size implements the gogo proto custom type interface.
@ -213,8 +210,9 @@ func UintOverflow(i *big.Int) error {
if i.Sign() < 0 { if i.Sign() < 0 {
return errors.New("non-positive integer") return errors.New("non-positive integer")
} }
if i.BitLen() > 256 {
return fmt.Errorf("bit length %d greater than 256", i.BitLen()) if g, w := i.BitLen(), MaxBitLen; g > w {
return fmt.Errorf("integer out of range; got: %d, max: %d", g, w)
} }
return nil return nil
} }

View File

@ -5,6 +5,7 @@ import (
"math" "math"
"math/big" "math/big"
"math/rand" "math/rand"
"strings"
"testing" "testing"
sdkmath "cosmossdk.io/math" sdkmath "cosmossdk.io/math"
@ -300,6 +301,7 @@ func TestRoundTripMarshalToUint(t *testing.T) {
1<<63 - 1, 1<<63 - 1,
1<<32 - 7, 1<<32 - 7,
1<<22 - 8, 1<<22 - 8,
math.MaxUint64,
} }
for _, value := range values { for _, value := range values {
@ -323,3 +325,39 @@ func TestRoundTripMarshalToUint(t *testing.T) {
}) })
} }
} }
func TestWeakUnmarshalNegativeSign(t *testing.T) {
neg10, _ := new(big.Int).SetString("-10", 0)
blob, err := neg10.MarshalText()
if err != nil {
t.Fatal(err)
}
ui := new(sdkmath.Uint)
err = ui.Unmarshal(blob)
if err == nil {
t.Fatal("Failed to catch the negative value")
}
if errStr := err.Error(); !strings.Contains(errStr, "non-positive") {
t.Fatalf("negative value not reported, got instead %q", errStr)
}
}
func TestWeakUnmarshalOverflow(t *testing.T) {
exp := new(big.Int).SetUint64(256)
pos10, _ := new(big.Int).SetString("10", 0)
exp10Pow256 := new(big.Int).Exp(pos10, exp, nil)
blob, err := exp10Pow256.MarshalText()
if err != nil {
t.Fatal(err)
}
ui := new(sdkmath.Uint)
err = ui.Unmarshal(blob)
if err == nil {
t.Fatal("Failed to catch the overflowed value")
}
if errStr := err.Error(); !strings.Contains(errStr, "out of range") {
t.Fatalf("out of range value not reported, got instead %q", errStr)
}
}