Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ethtypes: handle length overflow case #11082

Merged
merged 1 commit into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions chain/types/ethtypes/rlp.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func decodeRLP(data []byte) (res interface{}, consumed int, err error) {
return nil, 0, err
}
totalLen := 1 + strLenInBytes + strLen
if totalLen > len(data) {
if totalLen > len(data) || totalLen < 0 {
Copy link
Contributor

@fridrik01 fridrik01 Jul 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to do this check inside decodeLength (when checking lenInBytes+int(decodedLength) > len(data)) as that is overflowing the int64 to a negative number which is the root cause. That will also cover the case above when we are parsing lists which should have the same problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fridrik01 Isn't that the check you already added in #11079? Sorry, I'm a little confused.

In this PR I'm trying to catch an edge-case where decodedLength doesn't overflow, but decodedLength + strLenInBytes + 1 does.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arajasek Yes I added a check for negative decodedLength (see L160 below) but we can add a check for overflow in L163:

if err := binary.Read(r, binary.BigEndian, &decodedLength); err != nil {
return 0, xerrors.Errorf("invalid rlp data: cannot parse string length: %w", err)
}
if decodedLength < 0 {
return 0, xerrors.Errorf("invalid rlp data: negative string length")
}
if lenInBytes+int(decodedLength) > len(data) {
return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list")
}

So something like

totalLen := lenInBytes+decodedLength
if totalLen < 0 || totalLen > len(data) {
    return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list")
}

Whats happening is that decodedLength is close to Int64 max so when we add lenInBytes it overflows and becomes negative.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, got it! I think I'm gonna do both -- your suggestion SGTM, but we do have to check again in the caller because we wind up indexing data[totalLen + 1]

return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing string")
}
return data[1+strLenInBytes : totalLen], totalLen, nil
Expand All @@ -160,7 +160,9 @@ func decodeLength(data []byte, lenInBytes int) (length int, err error) {
if decodedLength < 0 {
return 0, xerrors.Errorf("invalid rlp data: negative string length")
}
if lenInBytes+int(decodedLength) > len(data) {

totalLength := lenInBytes + int(decodedLength)
if totalLength < 0 || totalLength > len(data) {
return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list")
}
return int(decodedLength), nil
Expand Down
3 changes: 2 additions & 1 deletion chain/types/ethtypes/rlp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,12 @@ func TestDecodeNegativeLength(t *testing.T) {
mustDecodeHex("0xbfffffffffffffff0041424344"),
mustDecodeHex("0xc1bFFF1111111111111111"),
mustDecodeHex("0xbFFF11111111111111"),
mustDecodeHex("0xbf7fffffffffffffff41424344"),
}

for _, tc := range testcases {
_, err := DecodeRLP(tc)
require.Error(t, err, "invalid rlp data: negative string length")
require.ErrorContains(t, err, "invalid rlp data")
}
}

Expand Down