summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOran Agra <oran@redislabs.com>2019-03-24 13:10:55 +0200
committerantirez <antirez@gmail.com>2019-04-10 18:47:32 +0200
commit3bbf9747a3a4bc9bd3942fd108c3bcd98770e0ce (patch)
tree71f91b0f19bdc3020858273426b37b14b3467ca7
parentf72f4ea311d31f7ce209218a96afb97490971d39 (diff)
downloadredis-3bbf9747a3a4bc9bd3942fd108c3bcd98770e0ce.tar.gz
slave corrupts replication stream when module blocked client uses large reply (or POSTPONED_ARRAY)
when redis appends the blocked client reply list to the real client, it didn't bother to check if it is in fact the master client. so a slave executing that module command will send replies to the master, causing the master to send the slave error responses, which will mess up the replication offset (slave will advance it's replication offset, and the master does not)
-rw-r--r--src/module.c7
-rw-r--r--src/networking.c13
-rw-r--r--src/server.h1
3 files changed, 15 insertions, 6 deletions
diff --git a/src/module.c b/src/module.c
index b8498ad99..26c1374ab 100644
--- a/src/module.c
+++ b/src/module.c
@@ -3706,12 +3706,7 @@ void moduleHandleBlockedClients(void) {
* We need to glue such replies to the client output buffer and
* free the temporary client we just used for the replies. */
if (c) {
- if (bc->reply_client->bufpos)
- addReplyString(c,bc->reply_client->buf,
- bc->reply_client->bufpos);
- if (listLength(bc->reply_client->reply))
- listJoin(c->reply,bc->reply_client->reply);
- c->reply_bytes += bc->reply_client->reply_bytes;
+ AddReplyFromClient(c, bc->reply_client);
}
freeClient(bc->reply_client);
diff --git a/src/networking.c b/src/networking.c
index 74b857e04..d6c291f85 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -628,6 +628,19 @@ void addReplySubcommandSyntaxError(client *c) {
sdsfree(cmd);
}
+/* Append 'src' client output buffers into 'dst' client output buffers.
+ * This function clears the output buffers of 'src' */
+void AddReplyFromClient(client *dst, client *src) {
+ if (prepareClientToWrite(dst) != C_OK)
+ return;
+ addReplyString(dst,src->buf, src->bufpos);
+ if (listLength(src->reply))
+ listJoin(dst->reply,src->reply);
+ dst->reply_bytes += src->reply_bytes;
+ src->reply_bytes = 0;
+ src->bufpos = 0;
+}
+
/* Copy 'src' client output buffers into 'dst' client output buffers.
* The function takes care of freeing the old output buffers of the
* destination client. */
diff --git a/src/server.h b/src/server.h
index 1f768e05c..d61e21db7 100644
--- a/src/server.h
+++ b/src/server.h
@@ -1435,6 +1435,7 @@ void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask);
void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask);
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask);
void addReplyString(client *c, const char *s, size_t len);
+void AddReplyFromClient(client *c, client *src);
void addReplyBulk(client *c, robj *obj);
void addReplyBulkCString(client *c, const char *s);
void addReplyBulkCBuffer(client *c, const void *p, size_t len);