From 80449719bd664bb0ed9c599765f6313f9b8a8303 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Tue, 27 Mar 2018 17:26:08 +0200 Subject: [PATCH] whisper: fix issue in topic list copy (#16381) - Fixes #16271. What was appeneded was a pointer to an object that changes during the iteration. - The topic is allocated as a 4-byte array, fill partial topics with 0s. Partial topics are currently disabled, but would crash as they rely on the presence of byte number 3. --- whisper/whisperv6/api.go | 7 ++-- whisper/whisperv6/api_test.go | 78 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 whisper/whisperv6/api_test.go diff --git a/whisper/whisperv6/api.go b/whisper/whisperv6/api.go index 96e2b17e7..3f3a082af 100644 --- a/whisper/whisperv6/api.go +++ b/whisper/whisperv6/api.go @@ -558,9 +558,10 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) { } if len(req.Topics) > 0 { - topics = make([][]byte, 0, len(req.Topics)) - for _, topic := range req.Topics { - topics = append(topics, topic[:]) + topics = make([][]byte, len(req.Topics)) + for i, topic := range req.Topics { + topics[i] = make([]byte, TopicLength) + copy(topics[i], topic[:]) } } diff --git a/whisper/whisperv6/api_test.go b/whisper/whisperv6/api_test.go new file mode 100644 index 000000000..004a41c94 --- /dev/null +++ b/whisper/whisperv6/api_test.go @@ -0,0 +1,78 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package whisperv6 + +import ( + "bytes" + "crypto/ecdsa" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + set "gopkg.in/fatih/set.v0" +) + +func TestMultipleTopicCopyInNewMessageFilter(t *testing.T) { + w := &Whisper{ + privateKeys: make(map[string]*ecdsa.PrivateKey), + symKeys: make(map[string][]byte), + envelopes: make(map[common.Hash]*Envelope), + expirations: make(map[uint32]*set.SetNonTS), + peers: make(map[*Peer]struct{}), + messageQueue: make(chan *Envelope, messageQueueLimit), + p2pMsgQueue: make(chan *Envelope, messageQueueLimit), + quit: make(chan struct{}), + syncAllowance: DefaultSyncAllowance, + } + w.filters = NewFilters(w) + + keyID, err := w.GenerateSymKey() + if err != nil { + t.Fatalf("Error generating symmetric key: %v", err) + } + api := PublicWhisperAPI{ + w: w, + lastUsed: make(map[string]time.Time), + } + + t1 := [4]byte{0xde, 0xea, 0xbe, 0xef} + t2 := [4]byte{0xca, 0xfe, 0xde, 0xca} + + crit := Criteria{ + SymKeyID: keyID, + Topics: []TopicType{TopicType(t1), TopicType(t2)}, + } + + _, err = api.NewMessageFilter(crit) + if err != nil { + t.Fatalf("Error creating the filter: %v", err) + } + + found := false + candidates := w.filters.getWatchersByTopic(TopicType(t1)) + for _, f := range candidates { + if len(f.Topics) == 2 { + if bytes.Equal(f.Topics[0], t1[:]) && bytes.Equal(f.Topics[1], t2[:]) { + found = true + } + } + } + + if !found { + t.Fatalf("Could not find filter with both topics") + } +}