From 80449719bd664bb0ed9c599765f6313f9b8a8303 Mon Sep 17 00:00:00 2001
From: Guillaume Ballet <gballet@gmail.com>
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 <http://www.gnu.org/licenses/>.
+
+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")
+	}
+}
-- 
GitLab