mirror of
https://github.com/luxfi/api.git
synced 2026-09-24 00:24:53 +00:00
fix(zap): bound element counts before make() to stop unbounded-alloc DoS
A decoded uint32 element count fed make([]T,count) before the per-element loop consumed any bytes, so a ~9-byte message with count=0xFFFFFFFF could drive a ~100GB allocation (OOM; the 16MB message cap and handler recover() do not bound it). Add Reader.ReadCount(), which rejects any count exceeding Remaining(), and use it in the 9 collection decoders across vm.go, sender.go, warp.go. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
+2
-2
@@ -22,7 +22,7 @@ func (m *SendRequestMsg) Encode(buf *Buffer) {
|
||||
|
||||
// Decode deserializes SendRequestMsg from the reader
|
||||
func (m *SendRequestMsg) Decode(r *Reader) error {
|
||||
count, err := r.ReadUint32()
|
||||
count, err := r.ReadCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -121,7 +121,7 @@ func (m *SendGossipMsg) Encode(buf *Buffer) {
|
||||
|
||||
// Decode deserializes SendGossipMsg from the reader
|
||||
func (m *SendGossipMsg) Decode(r *Reader) error {
|
||||
count, err := r.ReadUint32()
|
||||
count, err := r.ReadCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ func (m *BatchedParseBlockRequest) Encode(buf *Buffer) {
|
||||
|
||||
// Decode deserializes BatchedParseBlockRequest from the reader
|
||||
func (m *BatchedParseBlockRequest) Decode(r *Reader) error {
|
||||
count, err := r.ReadUint32()
|
||||
count, err := r.ReadCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -453,7 +453,7 @@ func (m *BatchedParseBlockResponse) Encode(buf *Buffer) {
|
||||
|
||||
// Decode deserializes BatchedParseBlockResponse from the reader
|
||||
func (m *BatchedParseBlockResponse) Decode(r *Reader) error {
|
||||
count, err := r.ReadUint32()
|
||||
count, err := r.ReadCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -513,7 +513,7 @@ func (m *GetAncestorsResponse) Encode(buf *Buffer) {
|
||||
|
||||
// Decode deserializes GetAncestorsResponse from the reader
|
||||
func (m *GetAncestorsResponse) Decode(r *Reader) error {
|
||||
count, err := r.ReadUint32()
|
||||
count, err := r.ReadCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -821,7 +821,7 @@ func (m *CreateHandlersResponse) Encode(buf *Buffer) {
|
||||
|
||||
// Decode deserializes CreateHandlersResponse from the reader
|
||||
func (m *CreateHandlersResponse) Decode(r *Reader) error {
|
||||
count, err := r.ReadUint32()
|
||||
count, err := r.ReadCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+3
-3
@@ -106,7 +106,7 @@ func (r *WarpBatchSignRequest) Encode(buf *Buffer) {
|
||||
|
||||
// Decode reads the request from the reader
|
||||
func (r *WarpBatchSignRequest) Decode(rd *Reader) error {
|
||||
count, err := rd.ReadUint32()
|
||||
count, err := rd.ReadCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func (r *WarpBatchSignResponse) Encode(buf *Buffer) {
|
||||
|
||||
// Decode reads the response from the reader
|
||||
func (r *WarpBatchSignResponse) Decode(rd *Reader) error {
|
||||
sigCount, err := rd.ReadUint32()
|
||||
sigCount, err := rd.ReadCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -150,7 +150,7 @@ func (r *WarpBatchSignResponse) Decode(rd *Reader) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
errCount, err := rd.ReadUint32()
|
||||
errCount, err := rd.ReadCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+16
@@ -304,6 +304,22 @@ func (r *Reader) Remaining() int {
|
||||
return len(r.data) - r.offset
|
||||
}
|
||||
|
||||
// ReadCount reads a uint32 element count and rejects any value larger than the
|
||||
// number of unread bytes. Every element costs at least one byte on the wire, so
|
||||
// a count exceeding Remaining() can never be satisfied by the payload. Rejecting
|
||||
// it here stops a hostile count (e.g. 0xFFFFFFFF) from driving a huge
|
||||
// make([]T, count) allocation before the per-element decode loop reaches EOF.
|
||||
func (r *Reader) ReadCount() (uint32, error) {
|
||||
n, err := r.ReadUint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if uint64(n) > uint64(r.Remaining()) {
|
||||
return 0, ErrInvalidMessage
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// WriteMessage writes a complete ZAP message with header
|
||||
func WriteMessage(w io.Writer, msgType MessageType, payload []byte) error {
|
||||
if len(payload) > MaxMessageSize {
|
||||
|
||||
Reference in New Issue
Block a user