diff options
author | Oran Agra <oran@redislabs.com> | 2023-01-16 13:49:30 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-16 13:49:30 +0200 |
commit | 1ec82e6e97e1db06a72ca505f9fbf6b981f31ef7 (patch) | |
tree | 6d15d2f79f93f70f671bdcab84b38f85b7a3f171 /src | |
parent | 395d801a2d978c3bb3139498c51825c393ae4450 (diff) | |
download | redis-1ec82e6e97e1db06a72ca505f9fbf6b981f31ef7.tar.gz |
Avoid integer overflows in SETRANGE and SORT (CVE-2022-35977) (#11720)
Authenticated users issuing specially crafted SETRANGE and SORT(_RO)
commands can trigger an integer overflow, resulting with Redis attempting
to allocate impossible amounts of memory and abort with an OOM panic.
Diffstat (limited to 'src')
-rw-r--r-- | src/sort.c | 6 | ||||
-rw-r--r-- | src/t_string.c | 17 |
2 files changed, 15 insertions, 8 deletions
diff --git a/src/sort.c b/src/sort.c index 3132d17e1..77f4cbbc4 100644 --- a/src/sort.c +++ b/src/sort.c @@ -328,8 +328,10 @@ void sortCommandGeneric(client *c, int readonly) { default: vectorlen = 0; serverPanic("Bad SORT type"); /* Avoid GCC warning */ } - /* Perform LIMIT start,count sanity checking. */ - start = (limit_start < 0) ? 0 : limit_start; + /* Perform LIMIT start,count sanity checking. + * And avoid integer overflow by limiting inputs to object sizes. */ + start = min(max(limit_start, 0), vectorlen); + limit_count = min(max(limit_count, -1), vectorlen); end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1; if (start >= vectorlen) { start = vectorlen-1; diff --git a/src/t_string.c b/src/t_string.c index 125f8ee86..6208d6a85 100644 --- a/src/t_string.c +++ b/src/t_string.c @@ -37,8 +37,14 @@ int getGenericCommand(client *c); * String Commands *----------------------------------------------------------------------------*/ -static int checkStringLength(client *c, long long size) { - if (!mustObeyClient(c) && size > server.proto_max_bulk_len) { +static int checkStringLength(client *c, long long size, long long append) { + if (mustObeyClient(c)) + return C_OK; + /* 'uint64_t' cast is there just to prevent undefined behavior on overflow */ + long long total = (uint64_t)size + append; + /* Test configured max-bulk-len represending a limit of the biggest string object, + * and also test for overflow. */ + if (total > server.proto_max_bulk_len || total < size || total < append) { addReplyError(c,"string exceeds maximum allowed size (proto-max-bulk-len)"); return C_ERR; } @@ -454,7 +460,7 @@ void setrangeCommand(client *c) { } /* Return when the resulting string exceeds allowed size */ - if (checkStringLength(c,offset+sdslen(value)) != C_OK) + if (checkStringLength(c,offset,sdslen(value)) != C_OK) return; o = createObject(OBJ_STRING,sdsnewlen(NULL, offset+sdslen(value))); @@ -474,7 +480,7 @@ void setrangeCommand(client *c) { } /* Return when the resulting string exceeds allowed size */ - if (checkStringLength(c,offset+sdslen(value)) != C_OK) + if (checkStringLength(c,offset,sdslen(value)) != C_OK) return; /* Create a copy when the object is shared or encoded. */ @@ -703,8 +709,7 @@ void appendCommand(client *c) { /* "append" is an argument, so always an sds */ append = c->argv[2]; - totlen = stringObjectLen(o)+sdslen(append->ptr); - if (checkStringLength(c,totlen) != C_OK) + if (checkStringLength(c,stringObjectLen(o),sdslen(append->ptr)) != C_OK) return; /* Append the value */ |