diff --git a/CHANGELOG.md b/CHANGELOG.md index 67f7aa7cf8..916471de36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (refactor) [\#685](https://github.com/line/lbm-sdk/pull/685) remove x/foundation UpdateValidatorAuthsProposal * (x/foundation) [\#686](https://github.com/line/lbm-sdk/pull/686) remove `Minthreshold` and `MinPercentage` from x/foundation config * (x/foundation) [\#693](https://github.com/line/lbm-sdk/pull/693) add pool to the state of x/foundation +* (x/wasm,distribution) [\#696](https://github.com/line/lbm-sdk/pull/696) x/wasm,distribution - add checking a file size before reading it * (x/foundation) [\#698](https://github.com/line/lbm-sdk/pull/698) update x/group relevant logic in x/foundation ### Bug Fixes diff --git a/internal/os/file.go b/internal/os/file.go new file mode 100644 index 0000000000..1a49f701c5 --- /dev/null +++ b/internal/os/file.go @@ -0,0 +1,58 @@ +package os + +import ( + "fmt" + "io" + "os" +) + +// ReadFileWithSizeLimit expanded os.ReadFile for checking the file size before reading it +func ReadFileWithSizeLimit(name string, sizeLimit int64) ([]byte, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + defer func() { + err := f.Close() + if err != nil { + fmt.Printf("Cannot close the file: %s\n", name) + } + }() + + var size int + if info, err := f.Stat(); err == nil { + size64 := info.Size() + // Check the file size + if size64 > sizeLimit { + return nil, fmt.Errorf("the file is too large: %s, size limit over > %d", name, sizeLimit) + } + if int64(int(size64)) == size64 { + size = int(size64) + } + } + size++ // one byte for final read at EOF + + // If a file claims a small size, read at least 512 bytes. + // In particular, files in Linux's /proc claim size 0 but + // then do not work right if read in small pieces, + // so an initial read of 1 byte would not work correctly. + if size < 512 { + size = 512 + } + + data := make([]byte, 0, size) + for { + if len(data) >= cap(data) { + d := append(data[:cap(data)], 0) + data = d[:len(data)] + } + n, err := f.Read(data[len(data):cap(data)]) + data = data[:len(data)+n] + if err != nil { + if err == io.EOF { + err = nil + } + return data, err + } + } +} diff --git a/internal/os/file_test.go b/internal/os/file_test.go new file mode 100644 index 0000000000..cafe8fd8a4 --- /dev/null +++ b/internal/os/file_test.go @@ -0,0 +1,42 @@ +package os + +import ( + "os" + "reflect" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestReadFileWithSizeLimit(t *testing.T) { + filename := "file.go" + file, err := os.ReadFile(filename) + require.NoError(t, err) + + type args struct { + name string + sizeLimit int64 + } + tests := []struct { + name string + args args + want []byte + wantErr bool + }{ + {"cannot open error", args{"", 0}, nil, true}, + {"size limit over error", args{filename, 0}, nil, true}, + {"simple reading file success", args{filename, 100000}, file, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ReadFileWithSizeLimit(tt.args.name, tt.args.sizeLimit) + if (err != nil) != tt.wantErr { + t.Errorf("ReadFileWithSizeLimit() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ReadFileWithSizeLimit() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/x/distribution/client/cli/utils.go b/x/distribution/client/cli/utils.go index d63702dacf..bb00838d3c 100644 --- a/x/distribution/client/cli/utils.go +++ b/x/distribution/client/cli/utils.go @@ -1,9 +1,8 @@ package cli import ( - "os" - "github.com/line/lbm-sdk/codec" + "github.com/line/lbm-sdk/internal/os" "github.com/line/lbm-sdk/x/distribution/types" ) @@ -11,7 +10,10 @@ import ( func ParseCommunityPoolSpendProposalWithDeposit(cdc codec.JSONCodec, proposalFile string) (types.CommunityPoolSpendProposalWithDeposit, error) { proposal := types.CommunityPoolSpendProposalWithDeposit{} - contents, err := os.ReadFile(proposalFile) + // 2M size limit is enough for a proposal. + // Check the proposals: + // https://hubble.figment.io/cosmos/chains/cosmoshub-4/governance + contents, err := os.ReadFileWithSizeLimit(proposalFile, 2*1024*1024) if err != nil { return proposal, err } diff --git a/x/wasm/client/cli/tx.go b/x/wasm/client/cli/tx.go index a516236066..9ce8ca0117 100644 --- a/x/wasm/client/cli/tx.go +++ b/x/wasm/client/cli/tx.go @@ -3,9 +3,10 @@ package cli import ( "errors" "fmt" - "os" "strconv" + "github.com/line/lbm-sdk/internal/os" + "github.com/spf13/cobra" flag "github.com/spf13/pflag" @@ -82,7 +83,7 @@ func StoreCodeCmd() *cobra.Command { } func parseStoreCodeArgs(file string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgStoreCode, error) { - wasm, err := os.ReadFile(file) + wasm, err := os.ReadFileWithSizeLimit(file, int64(types.MaxWasmSize)) if err != nil { return types.MsgStoreCode{}, err } @@ -264,7 +265,7 @@ func StoreCodeAndInstantiateContractCmd() *cobra.Command { } func parseStoreCodeAndInstantiateContractArgs(file string, initMsg string, sender sdk.AccAddress, flags *flag.FlagSet) (lbmtypes.MsgStoreCodeAndInstantiateContract, error) { - wasm, err := os.ReadFile(file) + wasm, err := os.ReadFileWithSizeLimit(file, int64(types.MaxWasmSize)) if err != nil { return lbmtypes.MsgStoreCodeAndInstantiateContract{}, err }