summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2011-12-31 16:09:46 +0100
committerantirez <antirez@gmail.com>2012-01-07 12:50:44 +0100
commite7b85b331556609c127e02e895aaf1e99cff67a4 (patch)
tree55002dc97962780f47c78548ad0dfc40185ccc6b
parenta5045d552c15f04ec3e95b9dda43d885739cfe36 (diff)
downloadredis-e7b85b331556609c127e02e895aaf1e99cff67a4.tar.gz
Protections against protocol desyncs, leading to infinite query buffer growing, due to nul-terms in specific bytes of the request or indefinitely long multi bulk or bulk count strings without newlines. This bug is related to Issue #141 as well.
-rw-r--r--src/networking.c29
-rw-r--r--src/redis.h1
2 files changed, 24 insertions, 6 deletions
diff --git a/src/networking.c b/src/networking.c
index 05af2ccf3..811853877 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -1,6 +1,8 @@
#include "redis.h"
#include <sys/uio.h>
+static void setProtocolError(redisClient *c, int pos);
+
void *dupClientReplyValue(void *o) {
incrRefCount((robj*)o);
return o;
@@ -678,8 +680,13 @@ int processInlineBuffer(redisClient *c) {
size_t querylen;
/* Nothing to do without a \r\n */
- if (newline == NULL)
+ if (newline == NULL) {
+ if (sdslen(c->querybuf) > REDIS_INLINE_MAX_SIZE) {
+ addReplyError(c,"Protocol error: too big inline request");
+ setProtocolError(c,0);
+ }
return REDIS_ERR;
+ }
/* Split the input buffer up to the \r\n */
querylen = newline-(c->querybuf);
@@ -729,8 +736,13 @@ int processMultibulkBuffer(redisClient *c) {
/* Multi bulk length cannot be read without a \r\n */
newline = strchr(c->querybuf,'\r');
- if (newline == NULL)
+ if (newline == NULL) {
+ if (sdslen(c->querybuf) > REDIS_INLINE_MAX_SIZE) {
+ addReplyError(c,"Protocol error: too big mbulk count string");
+ setProtocolError(c,0);
+ }
return REDIS_ERR;
+ }
/* Buffer should also contain \n */
if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2))
@@ -764,8 +776,13 @@ int processMultibulkBuffer(redisClient *c) {
/* Read bulk length if unknown */
if (c->bulklen == -1) {
newline = strchr(c->querybuf+pos,'\r');
- if (newline == NULL)
+ if (newline == NULL) {
+ if (sdslen(c->querybuf) > REDIS_INLINE_MAX_SIZE) {
+ addReplyError(c,"Protocol error: too big bulk count string");
+ setProtocolError(c,0);
+ }
break;
+ }
/* Buffer should also contain \n */
if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2))
@@ -806,9 +823,9 @@ int processMultibulkBuffer(redisClient *c) {
c->querybuf = sdsrange(c->querybuf,pos,-1);
/* We're done when c->multibulk == 0 */
- if (c->multibulklen == 0) {
- return REDIS_OK;
- }
+ if (c->multibulklen == 0) return REDIS_OK;
+
+ /* Still not read to process the command */
return REDIS_ERR;
}
diff --git a/src/redis.h b/src/redis.h
index 072153e8a..aca45ae8c 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -49,6 +49,7 @@
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
#define REDIS_SHARED_INTEGERS 10000
#define REDIS_REPLY_CHUNK_BYTES (5*1500) /* 5 TCP packets with default MTU */
+#define REDIS_INLINE_MAX_SIZE (1024*64) /* Max size of inline reads */
#define REDIS_MAX_LOGMSG_LEN 4096 /* Default maximum length of syslog messages */
#define REDIS_AUTO_AOFREWRITE_PERC 100
#define REDIS_AUTO_AOFREWRITE_MIN_SIZE (1024*1024)