Vulnerability: Redis is an open source, in-memory database that persists on disk. An integer overflow bug in the underlying string library can be used to corrupt the heap and potentially result with denial of service or remote code execution. The vulnerability involves changing the default proto-max-bulk-len configuration parameter to a very large value and constructing specially crafted network payloads or commands. The problem is fixed in Redis versions 6.2.6, 6.0.16 and 5.0.14. An additional workaround to mitigate the problem without patching the redis-server executable is to prevent users from modifying the proto-max-bulk-len configuration parameter. This can be done using ACL to restrict unprivileged users from using the CONFIG SET command.
Vulnerability ID: CVE-2021-41099
CWE: CWE-190
Severity score: 6.4
Project: https://github.com/redis/redis
Published: 2021-10-04
File: src/sds.c
Commit message: Fix integer overflow in _sdsMakeRoomFor (CVE-2021-41099)
Commit author: YiyuanGUO

Vulnerable version (before fix):
 void sdsclear(sds s) { sds sdsMakeRoomFor(sds s, size_t addlen) {     void *sh, *newsh;     size_t avail = sdsavail(s);     size_t len, newlen;     char type, oldtype = s[-1] & SDS_TYPE_MASK;     int hdrlen;  sds sdsMakeRoomFor(sds s, size_t addlen) {      len = sdslen(s);     sh = (char*)s-sdsHdrSize(oldtype);     newlen = (len+addlen);     assert(newlen > len);   /* Catch size_t overflow */     if (newlen < SDS_MAX_PREALLOC)         newlen *= 2; sds sdsMakeRoomFor(sds s, size_t addlen) {     if (type == SDS_TYPE_5) type = SDS_TYPE_8;      hdrlen = sdsHdrSize(type);     assert(hdrlen + newlen + 1 > len);  /* Catch size_t overflow */     if (oldtype==type) {         newsh = s_realloc(sh, hdrlen+newlen+1);         if (newsh == NULL) return NULL;

Fixed version (after fix):
 void sdsclear(sds s) { sds sdsMakeRoomFor(sds s, size_t addlen) {     void *sh, *newsh;     size_t avail = sdsavail(s);     size_t len, newlen, reqlen;     char type, oldtype = s[-1] & SDS_TYPE_MASK;     int hdrlen;  sds sdsMakeRoomFor(sds s, size_t addlen) {      len = sdslen(s);     sh = (char*)s-sdsHdrSize(oldtype);     reqlen = newlen = (len+addlen);     assert(newlen > len);   /* Catch size_t overflow */     if (newlen < SDS_MAX_PREALLOC)         newlen *= 2; sds sdsMakeRoomFor(sds s, size_t addlen) {     if (type == SDS_TYPE_5) type = SDS_TYPE_8;      hdrlen = sdsHdrSize(type);     assert(hdrlen + newlen + 1 > reqlen);  /* Catch size_t overflow */     if (oldtype==type) {         newsh = s_realloc(sh, hdrlen+newlen+1);         if (newsh == NULL) return NULL;

Patch:
patch: @@ -205,7 +205,7 @@ void sdsclear(sds s) {
 sds sdsMakeRoomFor(sds s, size_t addlen) {
     void *sh, *newsh;
     size_t avail = sdsavail(s);
-    size_t len, newlen;
+    size_t len, newlen, reqlen;
     char type, oldtype = s[-1] & SDS_TYPE_MASK;
     int hdrlen;
 
@@ -214,7 +214,7 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
 
     len = sdslen(s);
     sh = (char*)s-sdsHdrSize(oldtype);
-    newlen = (len+addlen);
+    reqlen = newlen = (len+addlen);
     assert(newlen > len);   /* Catch size_t overflow */
     if (newlen < SDS_MAX_PREALLOC)
         newlen *= 2;
@@ -229,7 +229,7 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
     if (type == SDS_TYPE_5) type = SDS_TYPE_8;
 
     hdrlen = sdsHdrSize(type);
-    assert(hdrlen + newlen + 1 > len);  /* Catch size_t overflow */
+    assert(hdrlen + newlen + 1 > reqlen);  /* Catch size_t overflow */
     if (oldtype==type) {
         newsh = s_realloc(sh, hdrlen+newlen+1);
         if (newsh == NULL) return NULL;
path: src/sds.c