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

proto: fix uint64->int overflow in table unmarshal #461

Merged
merged 3 commits into from
Nov 29, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
10 changes: 9 additions & 1 deletion proto/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1306,7 +1306,7 @@ func (*NNIMessage) Reset() {}
func (*NNIMessage) String() string { return "" }
func (*NNIMessage) ProtoMessage() {}

type NMMessage struct {}
type NMMessage struct{}

func (*NMMessage) Reset() {}
func (*NMMessage) String() string { return "" }
Expand Down Expand Up @@ -1505,6 +1505,14 @@ func TestVarintOverflow(t *testing.T) {
}
}

func TestBytesWithInvalidLengthInGroup(t *testing.T) {
// Overflowing a 64-bit length should not be allowed.
b := []byte{0xbb, 0x30, 0xb2, 0x30, 0xb0, 0xb2, 0x83, 0xf1, 0xb0, 0xb2, 0xef, 0xbf, 0xbd, 0x01}
if err := Unmarshal(b, new(MyMessage)); err == nil {
t.Fatalf("Overflowed uint64 length without error")
}
}

func TestUnmarshalFuzz(t *testing.T) {
const N = 1000
seed := time.Now().UnixNano()
Expand Down
2 changes: 1 addition & 1 deletion proto/table_unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -1849,7 +1849,7 @@ func findEndGroup(b []byte) (int, int) {
return -1, -1
}
i += k
if i+int(m) > len(b) {
if uint64(len(b)) < uint64(i)+m {
Copy link
Member

@dsnet dsnet Nov 29, 2017

Choose a reason for hiding this comment

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

Can't this still overflow with malicious values of m? E.g., if m was set to math.MaxUint64-i+1, then this check will never trigger.

Since, we know that i ≤ len(b), wouldn't a more safe check be: uint64(len(b)-i) < m since the LHS is guaranteed to be a positive value?

Similarly, we should also protect the WireFixed32 and WireFixed64 cases to be of this form, although it is far less likely those can be exploited.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The i+m operation can wrap, although the harm is limited to misinterpreting the contents of the buffer--it can't panic, because we've ensured that the wrapped i+m is within the bounds of b.

Rewrote it anyway to be more correct. Fixed one other existing case where this could wrap at the same time.

return -1, -1
}
i += int(m)
Expand Down