diff options
author | antirez <antirez@gmail.com> | 2011-12-31 16:09:46 +0100 |
---|---|---|
committer | antirez <antirez@gmail.com> | 2012-01-07 12:50:44 +0100 |
commit | e7b85b331556609c127e02e895aaf1e99cff67a4 (patch) | |
tree | 55002dc97962780f47c78548ad0dfc40185ccc6b | |
parent | a5045d552c15f04ec3e95b9dda43d885739cfe36 (diff) | |
download | redis-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.c | 29 | ||||
-rw-r--r-- | src/redis.h | 1 |
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) |