sdsrange overflow fix (#830)

Fix overflow bug in `sdsrange`
This commit is contained in:
Michael Grunder 2020-06-07 14:38:16 -07:00 committed by GitHub
parent c726723545
commit 6448f735d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 30 additions and 20 deletions

View File

@ -920,17 +920,17 @@ int redisBufferWrite(redisContext *c, int *done) {
return REDIS_ERR; return REDIS_ERR;
if (sdslen(c->obuf) > 0) { if (sdslen(c->obuf) > 0) {
int nwritten = c->funcs->write(c); ssize_t nwritten = c->funcs->write(c);
if (nwritten < 0) { if (nwritten < 0) {
return REDIS_ERR; return REDIS_ERR;
} else if (nwritten > 0) { } else if (nwritten > 0) {
if (nwritten == (signed)sdslen(c->obuf)) { if (nwritten == (ssize_t)sdslen(c->obuf)) {
sdsfree(c->obuf); sdsfree(c->obuf);
c->obuf = sdsempty(); c->obuf = sdsempty();
if (c->obuf == NULL) if (c->obuf == NULL)
goto oom; goto oom;
} else { } else {
sdsrange(c->obuf,nwritten,-1); if (sdsrange(c->obuf,nwritten,-1) < 0) goto oom;
} }
} }
} }

View File

@ -39,6 +39,7 @@
#include <sys/time.h> /* for struct timeval */ #include <sys/time.h> /* for struct timeval */
#else #else
struct timeval; /* forward declaration */ struct timeval; /* forward declaration */
typedef long long ssize_t;
#endif #endif
#include <stdint.h> /* uintXX_t, etc */ #include <stdint.h> /* uintXX_t, etc */
#include "sds.h" /* for sds */ #include "sds.h" /* for sds */
@ -200,8 +201,8 @@ typedef struct redisContextFuncs {
void (*free_privdata)(void *); void (*free_privdata)(void *);
void (*async_read)(struct redisAsyncContext *); void (*async_read)(struct redisAsyncContext *);
void (*async_write)(struct redisAsyncContext *); void (*async_write)(struct redisAsyncContext *);
int (*read)(struct redisContext *, char *, size_t); ssize_t (*read)(struct redisContext *, char *, size_t);
int (*write)(struct redisContext *); ssize_t (*write)(struct redisContext *);
} redisContextFuncs; } redisContextFuncs;
/* Context for a connection to Redis */ /* Context for a connection to Redis */

8
net.c
View File

@ -57,8 +57,8 @@ void redisNetClose(redisContext *c) {
} }
} }
int redisNetRead(redisContext *c, char *buf, size_t bufcap) { ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
int nread = recv(c->fd, buf, bufcap, 0); ssize_t nread = recv(c->fd, buf, bufcap, 0);
if (nread == -1) { if (nread == -1) {
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */ /* Try again later */
@ -79,8 +79,8 @@ int redisNetRead(redisContext *c, char *buf, size_t bufcap) {
} }
} }
int redisNetWrite(redisContext *c) { ssize_t redisNetWrite(redisContext *c) {
int nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0); ssize_t nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0);
if (nwritten < 0) { if (nwritten < 0) {
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */ /* Try again later */

4
net.h
View File

@ -38,8 +38,8 @@
#include "hiredis.h" #include "hiredis.h"
void redisNetClose(redisContext *c); void redisNetClose(redisContext *c);
int redisNetRead(redisContext *c, char *buf, size_t bufcap); ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap);
int redisNetWrite(redisContext *c); ssize_t redisNetWrite(redisContext *c);
int redisCheckSocketError(redisContext *c); int redisCheckSocketError(redisContext *c);
int redisContextSetTimeout(redisContext *c, const struct timeval tv); int redisContextSetTimeout(redisContext *c, const struct timeval tv);

2
read.c
View File

@ -720,7 +720,7 @@ int redisReaderGetReply(redisReader *r, void **reply) {
/* Discard part of the buffer when we've consumed at least 1k, to avoid /* Discard part of the buffer when we've consumed at least 1k, to avoid
* doing unnecessary calls to memmove() in sds.c. */ * doing unnecessary calls to memmove() in sds.c. */
if (r->pos >= 1024) { if (r->pos >= 1024) {
sdsrange(r->buf,r->pos,-1); if (sdsrange(r->buf,r->pos,-1) < 0) return REDIS_ERR;
r->pos = 0; r->pos = 0;
r->len = sdslen(r->buf); r->len = sdslen(r->buf);
} }

15
sds.c
View File

@ -36,6 +36,7 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
#include <limits.h>
#include "sds.h" #include "sds.h"
#include "sdsalloc.h" #include "sdsalloc.h"
@ -713,15 +714,20 @@ sds sdstrim(sds s, const char *cset) {
* *
* The string is modified in-place. * The string is modified in-place.
* *
* Return value:
* -1 (error) if sdslen(s) is larger than maximum positive ssize_t value.
* 0 on success.
*
* Example: * Example:
* *
* s = sdsnew("Hello World"); * s = sdsnew("Hello World");
* sdsrange(s,1,-1); => "ello World" * sdsrange(s,1,-1); => "ello World"
*/ */
void sdsrange(sds s, int start, int end) { int sdsrange(sds s, ssize_t start, ssize_t end) {
size_t newlen, len = sdslen(s); size_t newlen, len = sdslen(s);
if (len > SSIZE_MAX) return -1;
if (len == 0) return; if (len == 0) return 0;
if (start < 0) { if (start < 0) {
start = len+start; start = len+start;
if (start < 0) start = 0; if (start < 0) start = 0;
@ -732,9 +738,9 @@ void sdsrange(sds s, int start, int end) {
} }
newlen = (start > end) ? 0 : (end-start)+1; newlen = (start > end) ? 0 : (end-start)+1;
if (newlen != 0) { if (newlen != 0) {
if (start >= (signed)len) { if (start >= (ssize_t)len) {
newlen = 0; newlen = 0;
} else if (end >= (signed)len) { } else if (end >= (ssize_t)len) {
end = len-1; end = len-1;
newlen = (start > end) ? 0 : (end-start)+1; newlen = (start > end) ? 0 : (end-start)+1;
} }
@ -744,6 +750,7 @@ void sdsrange(sds s, int start, int end) {
if (start && newlen) memmove(s, s+start, newlen); if (start && newlen) memmove(s, s+start, newlen);
s[newlen] = 0; s[newlen] = 0;
sdssetlen(s,newlen); sdssetlen(s,newlen);
return 0;
} }
/* Apply tolower() to every character of the sds string 's'. */ /* Apply tolower() to every character of the sds string 's'. */

4
sds.h
View File

@ -36,6 +36,8 @@
#define SDS_MAX_PREALLOC (1024*1024) #define SDS_MAX_PREALLOC (1024*1024)
#ifdef _MSC_VER #ifdef _MSC_VER
#define __attribute__(x) #define __attribute__(x)
typedef long long ssize_t;
#define SSIZE_MAX (LLONG_MAX >> 1)
#endif #endif
#include <sys/types.h> #include <sys/types.h>
@ -239,7 +241,7 @@ sds sdscatprintf(sds s, const char *fmt, ...);
sds sdscatfmt(sds s, char const *fmt, ...); sds sdscatfmt(sds s, char const *fmt, ...);
sds sdstrim(sds s, const char *cset); sds sdstrim(sds s, const char *cset);
void sdsrange(sds s, int start, int end); int sdsrange(sds s, ssize_t start, ssize_t end);
void sdsupdatelen(sds s); void sdsupdatelen(sds s);
void sdsclear(sds s); void sdsclear(sds s);
int sdscmp(const sds s1, const sds s2); int sdscmp(const sds s1, const sds s2);

View File

@ -51,7 +51,7 @@
#include <stddef.h> #include <stddef.h>
#ifdef _MSC_VER #ifdef _MSC_VER
typedef signed long ssize_t; typedef long long ssize_t;
#endif #endif
/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */ /* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */

4
ssl.c
View File

@ -392,7 +392,7 @@ static void redisSSLFree(void *privdata){
hi_free(rsc); hi_free(rsc);
} }
static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) { static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
redisSSL *rssl = c->privdata; redisSSL *rssl = c->privdata;
int nread = SSL_read(rssl->ssl, buf, bufcap); int nread = SSL_read(rssl->ssl, buf, bufcap);
@ -434,7 +434,7 @@ static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
} }
} }
static int redisSSLWrite(redisContext *c) { static ssize_t redisSSLWrite(redisContext *c) {
redisSSL *rssl = c->privdata; redisSSL *rssl = c->privdata;
size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf); size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf);