From fab8f0e884fad3ba3560236338588ed78281beb0 Mon Sep 17 00:00:00 2001 From: Pino' Surace Date: Thu, 29 Jun 2023 13:11:26 +0200 Subject: [PATCH] Remove check for wasm limit size in state sync --- x/wasm/client/cli/gov_tx.go | 2 +- x/wasm/ioutils/ioutil.go | 16 +++++++++++- x/wasm/ioutils/ioutil_test.go | 47 ++++++++++++++++++++++++++++++++++- x/wasm/keeper/keeper.go | 4 +-- x/wasm/keeper/snapshotter.go | 2 +- 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/x/wasm/client/cli/gov_tx.go b/x/wasm/client/cli/gov_tx.go index be6114b958..c53620c7f3 100644 --- a/x/wasm/client/cli/gov_tx.go +++ b/x/wasm/client/cli/gov_tx.go @@ -129,7 +129,7 @@ func parseVerificationFlags(gzippedWasm []byte, flags *flag.FlagSet) (string, st // wasm is gzipped in parseStoreCodeArgs // checksum generation will be decoupled here // reference https://github.com/CosmWasm/wasmvm/issues/359 - raw, err := ioutils.Uncompress(gzippedWasm, uint64(types.MaxWasmSize)) + raw, err := ioutils.UncompressWithLimit(gzippedWasm, uint64(types.MaxWasmSize)) if err != nil { return "", "", nil, fmt.Errorf("invalid zip: %w", err) } diff --git a/x/wasm/ioutils/ioutil.go b/x/wasm/ioutils/ioutil.go index b671e5ad65..477c6f389f 100644 --- a/x/wasm/ioutils/ioutil.go +++ b/x/wasm/ioutils/ioutil.go @@ -11,7 +11,21 @@ import ( ) // Uncompress expects a valid gzip source to unpack or fails. See IsGzip -func Uncompress(gzipSrc []byte, limit uint64) ([]byte, error) { +func Uncompress(gzipSrc []byte) ([]byte, error) { + zr, err := gzip.NewReader(bytes.NewReader(gzipSrc)) + if err != nil { + return nil, err + } + zr.Multistream(false) + defer zr.Close() + + bz, err := io.ReadAll(zr) + return bz, err +} + +// UncompressWithLimit fails if wasm size exceeds the limit. +// It expects a valid gzip source to unpack or fails. See IsGzip +func UncompressWithLimit(gzipSrc []byte, limit uint64) ([]byte, error) { if uint64(len(gzipSrc)) > limit { return nil, types.ErrLimit.Wrapf("max %d bytes", limit) } diff --git a/x/wasm/ioutils/ioutil_test.go b/x/wasm/ioutils/ioutil_test.go index 3cd1b5c2dc..e9108e549e 100644 --- a/x/wasm/ioutils/ioutil_test.go +++ b/x/wasm/ioutils/ioutil_test.go @@ -23,6 +23,51 @@ func TestUncompress(t *testing.T) { wasmGzipped, err := os.ReadFile("../keeper/testdata/hackatom.wasm.gzip") require.NoError(t, err) + specs := map[string]struct { + src []byte + expError error + expResult []byte + }{ + "handle wasm compressed": { + src: wasmGzipped, + expResult: wasmRaw, + }, + "handle gzip identifier only": { + src: gzipIdent, + expError: io.ErrUnexpectedEOF, + }, + "handle broken gzip": { + src: append(gzipIdent, byte(0x1)), + expError: io.ErrUnexpectedEOF, + }, + "handle incomplete gzip": { + src: wasmGzipped[:len(wasmGzipped)-5], + expError: io.ErrUnexpectedEOF, + }, + "handle limit gzip output": { + src: asGzip(bytes.Repeat([]byte{0x1}, 400_000)), + expResult: bytes.Repeat([]byte{0x1}, 400_000), + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + r, err := Uncompress(spec.src) + require.True(t, errors.Is(spec.expError, err), "exp %v got %+v", spec.expError, err) + if spec.expError != nil { + return + } + assert.Equal(t, spec.expResult, r) + }) + } +} + +func TestUncompressWithLimit(t *testing.T) { + wasmRaw, err := os.ReadFile("../keeper/testdata/hackatom.wasm") + require.NoError(t, err) + + wasmGzipped, err := os.ReadFile("../keeper/testdata/hackatom.wasm.gzip") + require.NoError(t, err) + const maxSize = 400_000 specs := map[string]struct { @@ -61,7 +106,7 @@ func TestUncompress(t *testing.T) { } for msg, spec := range specs { t.Run(msg, func(t *testing.T) { - r, err := Uncompress(spec.src, maxSize) + r, err := UncompressWithLimit(spec.src, maxSize) require.True(t, errors.Is(spec.expError, err), "exp %v got %+v", spec.expError, err) if spec.expError != nil { return diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 491f094a3b..2b91ede4b7 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -170,7 +170,7 @@ func (k Keeper) create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, if ioutils.IsGzip(wasmCode) { ctx.GasMeter().ConsumeGas(k.gasRegister.UncompressCosts(len(wasmCode)), "Uncompress gzip bytecode") - wasmCode, err = ioutils.Uncompress(wasmCode, uint64(types.MaxWasmSize)) + wasmCode, err = ioutils.UncompressWithLimit(wasmCode, uint64(types.MaxWasmSize)) if err != nil { return 0, checksum, types.ErrCreateFailed.Wrap(errorsmod.Wrap(err, "uncompress wasm archive").Error()) } @@ -212,7 +212,7 @@ func (k Keeper) storeCodeInfo(ctx sdk.Context, codeID uint64, codeInfo types.Cod func (k Keeper) importCode(ctx sdk.Context, codeID uint64, codeInfo types.CodeInfo, wasmCode []byte) error { if ioutils.IsGzip(wasmCode) { var err error - wasmCode, err = ioutils.Uncompress(wasmCode, uint64(types.MaxWasmSize)) + wasmCode, err = ioutils.UncompressWithLimit(wasmCode, uint64(types.MaxWasmSize)) if err != nil { return types.ErrCreateFailed.Wrap(errorsmod.Wrap(err, "uncompress wasm archive").Error()) } diff --git a/x/wasm/keeper/snapshotter.go b/x/wasm/keeper/snapshotter.go index 4ac85b46fe..10fb61dba5 100644 --- a/x/wasm/keeper/snapshotter.go +++ b/x/wasm/keeper/snapshotter.go @@ -99,7 +99,7 @@ func restoreV1(_ sdk.Context, k *Keeper, compressedCode []byte) error { if !ioutils.IsGzip(compressedCode) { return types.ErrInvalid.Wrap("not a gzip") } - wasmCode, err := ioutils.Uncompress(compressedCode, uint64(types.MaxWasmSize)) + wasmCode, err := ioutils.Uncompress(compressedCode) if err != nil { return errorsmod.Wrap(types.ErrCreateFailed, err.Error()) }