diff options
author | Oran Agra <oran@redislabs.com> | 2021-10-04 12:11:02 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-04 12:11:02 +0300 |
commit | c5e6a6204c4cf57f85e7c83a9b4e99f1a7204fd2 (patch) | |
tree | 9f55ffb0f03b07391b4796331aabcb7881ba80ae /src/ziplist.c | |
parent | fba15850e5c31666e4c3560a3be7fd034fa7e2b6 (diff) | |
download | redis-c5e6a6204c4cf57f85e7c83a9b4e99f1a7204fd2.tar.gz |
Fix ziplist and listpack overflows and truncations (CVE-2021-32627, CVE-2021-32628) (#9589)
- fix possible heap corruption in ziplist and listpack resulting by trying to
allocate more than the maximum size of 4GB.
- prevent ziplist (hash and zset) from reaching size of above 1GB, will be
converted to HT encoding, that's not a useful size.
- prevent listpack (stream) from reaching size of above 1GB.
- XADD will start a new listpack if the new record may cause the previous
listpack to grow over 1GB.
- XADD will respond with an error if a single stream record is over 1GB
- List type (ziplist in quicklist) was truncating strings that were over 4GB,
now it'll respond with an error.
Co-authored-by: sundb <sundbcn@gmail.com>
Diffstat (limited to 'src/ziplist.c')
-rw-r--r-- | src/ziplist.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/src/ziplist.c b/src/ziplist.c index 34adad622..e4ad7b145 100644 --- a/src/ziplist.c +++ b/src/ziplist.c @@ -267,6 +267,17 @@ ZIPLIST_LENGTH(zl) = intrev16ifbe(intrev16ifbe(ZIPLIST_LENGTH(zl))+incr); \ } +/* Don't let ziplists grow over 1GB in any case, don't wanna risk overflow in + * zlbytes */ +#define ZIPLIST_MAX_SAFETY_SIZE (1<<30) +int ziplistSafeToAdd(unsigned char* zl, size_t add) { + size_t len = zl? ziplistBlobLen(zl): 0; + if (len + add > ZIPLIST_MAX_SAFETY_SIZE) + return 0; + return 1; +} + + /* We use this function to receive information about a ziplist entry. * Note that this is not how the data is actually encoded, is just what we * get filled by a function in order to operate more easily. */ @@ -709,7 +720,8 @@ unsigned char *ziplistNew(void) { } /* Resize the ziplist. */ -unsigned char *ziplistResize(unsigned char *zl, unsigned int len) { +unsigned char *ziplistResize(unsigned char *zl, size_t len) { + assert(len < UINT32_MAX); zl = zrealloc(zl,len); ZIPLIST_BYTES(zl) = intrev32ifbe(len); zl[len-1] = ZIP_END; @@ -1070,6 +1082,9 @@ unsigned char *ziplistMerge(unsigned char **first, unsigned char **second) { /* Combined zl length should be limited within UINT16_MAX */ zllength = zllength < UINT16_MAX ? zllength : UINT16_MAX; + /* larger values can't be stored into ZIPLIST_BYTES */ + assert(zlbytes < UINT32_MAX); + /* Save offset positions before we start ripping memory apart. */ size_t first_offset = intrev32ifbe(ZIPLIST_TAIL_OFFSET(*first)); size_t second_offset = intrev32ifbe(ZIPLIST_TAIL_OFFSET(*second)); |