mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 09:53:48 +00:00
whisper: Extra unit tests
There are some potential issue because the Msg.Size field is a uint32 and it is often compared to the output of len() which is an int. The libp2p WriteMsg() and ReadMsg() methods now check for a potential overflow and will return an error if they detect one.
This commit is contained in:
parent
2616668d0f
commit
c94fb219c0
2 changed files with 122 additions and 2 deletions
|
|
@ -20,6 +20,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
inet "github.com/libp2p/go-libp2p-net"
|
||||
|
|
@ -69,13 +70,21 @@ func (stream *LibP2PStream) ReadMsg() (p2p.Msg, error) {
|
|||
// WriteMsg implements the MsgReadWriter interface to write messages
|
||||
// to lilbp2p streams.
|
||||
func (stream *LibP2PStream) WriteMsg(msg p2p.Msg) error {
|
||||
// Refuse to write messages with an unsigned size greater than
|
||||
// a signed 32-bit integer size. This is because len() returns
|
||||
// an int, forcing a conversion at some locations in the code,
|
||||
// and on some blatforms that might cause an issue.
|
||||
if msg.Size > math.MaxInt32 {
|
||||
return fmt.Errorf("Payload size must be a maximum of %d bytes", math.MaxInt32)
|
||||
}
|
||||
|
||||
data := make([]byte, msg.Size+codeLength+payloadSizeLength)
|
||||
|
||||
binary.LittleEndian.PutUint64(data[0:codeLength], msg.Code)
|
||||
binary.LittleEndian.PutUint32(data[codeLength:codeLength+payloadSizeLength], msg.Size)
|
||||
|
||||
nbytes, err := msg.Payload.Read(data[codeLength+payloadSizeLength:])
|
||||
if (nbytes&0xFFFFFFFF) != nbytes || uint32(nbytes) != msg.Size {
|
||||
if nbytes > math.MaxInt32 || uint32(nbytes) != msg.Size {
|
||||
return fmt.Errorf("Invalid size read in libp2p stream: read %d bytes, was expecting %d bytes", nbytes, msg.Size)
|
||||
} else if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package whisperv6
|
||||
|
||||
import (
|
||||
"math"
|
||||
"encoding/binary"
|
||||
"context"
|
||||
"bytes"
|
||||
|
|
@ -135,6 +136,8 @@ func TestSimpleDecode(t *testing.T) {
|
|||
hosts := createTestNetwork(ctx, t, 2)
|
||||
|
||||
hosts[0].SetStreamHandler(testProtocolID, func (s inet.Stream) {
|
||||
defer s.Close()
|
||||
|
||||
lps := LibP2PStream{
|
||||
stream: s,
|
||||
}
|
||||
|
|
@ -163,4 +166,112 @@ func TestSimpleDecode(t *testing.T) {
|
|||
}
|
||||
|
||||
stream.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleCodeDecode(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
hosts := createTestNetwork(ctx, t, 2)
|
||||
|
||||
code := rand.Uint64()
|
||||
size := rand.Uint32() % 512
|
||||
payload := make([]byte, size)
|
||||
n, err := rand.Read(payload)
|
||||
if err != nil || uint32(n) != size {
|
||||
t.Fatalf("Read %d random bytes instead of the expected %d, err: %v", n, size, err)
|
||||
}
|
||||
|
||||
hosts[0].SetStreamHandler(testProtocolID, func (s inet.Stream) {
|
||||
defer s.Close()
|
||||
|
||||
lps := LibP2PStream{
|
||||
stream: s,
|
||||
}
|
||||
|
||||
msg, err := lps.ReadMsg()
|
||||
if err != nil {
|
||||
t.Fatalf("Error decoding message: %s", err)
|
||||
}
|
||||
|
||||
if msg.Code != code {
|
||||
t.Fatalf("Error decoding message code %d instead of %d", msg.Code, code)
|
||||
}
|
||||
if int(msg.Size) != len(payload) {
|
||||
t.Fatalf("Error decoding message size %d instead of %d", msg.Size, len(payload))
|
||||
}
|
||||
|
||||
readPayload := make([]byte, len(payload))
|
||||
sizeRead, err := msg.Payload.Read(readPayload)
|
||||
if err != nil || sizeRead != len(payload) {
|
||||
t.Fatalf("Error reading payload from source: %s (%d bytes read for %d expected)", err, sizeRead, len(payload))
|
||||
} else if !bytes.Equal(payload, readPayload) {
|
||||
t.Fatal("Encoded payload differ from source")
|
||||
}
|
||||
})
|
||||
stream, err := hosts[1].NewStream(ctx, hosts[0].ID(), testProtocolID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := p2p.Msg{
|
||||
Code: code,
|
||||
Size: size,
|
||||
Payload: bytes.NewReader(payload),
|
||||
}
|
||||
|
||||
lps := LibP2PStream{
|
||||
stream: stream,
|
||||
}
|
||||
|
||||
err = lps.WriteMsg(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error encoding a message to the stream: %s", err)
|
||||
}
|
||||
|
||||
stream.Close()
|
||||
}
|
||||
|
||||
func TestMaxWriteSize(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
hosts := createTestNetwork(ctx, t, 2)
|
||||
|
||||
code := rand.Uint64()
|
||||
// This isn't the size that will be reported, but if I actually
|
||||
// require 2GB or RAM the CI servers will fail.
|
||||
size := 10
|
||||
payload := make([]byte, size)
|
||||
n, err := rand.Read(payload)
|
||||
if err != nil || n != size {
|
||||
t.Fatalf("Read %d random bytes instead of the expected %d, err: %v", n, size, err)
|
||||
}
|
||||
|
||||
hosts[0].SetStreamHandler(testProtocolID, func (s inet.Stream) {
|
||||
defer s.Close()
|
||||
|
||||
dummy := []byte{0x0}
|
||||
_, _ = s.Read(dummy)
|
||||
})
|
||||
stream, err := hosts[1].NewStream(ctx, hosts[0].ID(), testProtocolID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := p2p.Msg{
|
||||
Code: code,
|
||||
Size: math.MaxInt32+1,
|
||||
Payload: bytes.NewReader(payload),
|
||||
}
|
||||
|
||||
lps := LibP2PStream{
|
||||
stream: stream,
|
||||
}
|
||||
|
||||
err = lps.WriteMsg(msg)
|
||||
|
||||
if err.Error() != "Payload size must be a maximum of 2147483647 bytes" {
|
||||
t.Fatal("Should have returned an error with invalid payload size")
|
||||
}
|
||||
|
||||
stream.Close()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue