diff options
author | Oran Agra <oran@redislabs.com> | 2020-11-22 21:22:49 +0200 |
---|---|---|
committer | Oran Agra <oran@redislabs.com> | 2020-12-06 14:54:34 +0200 |
commit | 7ca00d694d44be13a3ff9ff1c96b49222ac9463b (patch) | |
tree | 3567297f9a6e7b7730025024cf33c60d4ccf17de /src/dict.c | |
parent | 3716950cfc389c0f7ed13fac5bd205173c2d8189 (diff) | |
download | redis-7ca00d694d44be13a3ff9ff1c96b49222ac9463b.tar.gz |
Sanitize dump payload: fail RESTORE if memory allocation fails
When RDB input attempts to make a huge memory allocation that fails,
RESTORE should fail gracefully rather than die with panic
Diffstat (limited to 'src/dict.c')
-rw-r--r-- | src/dict.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/src/dict.c b/src/dict.c index cca5aa921..4736dacd5 100644 --- a/src/dict.c +++ b/src/dict.c @@ -143,9 +143,13 @@ int dictResize(dict *d) return dictExpand(d, minimal); } -/* Expand or create the hash table */ -int dictExpand(dict *d, unsigned long size) +/* Expand or create the hash table, + * when malloc_failed is non-NULL, it'll avoid panic if malloc fails (in which case it'll be set to 1). + * Returns DICT_OK if expand was performed, and DICT_ERR if skipped. */ +int _dictExpand(dict *d, unsigned long size, int* malloc_failed) { + if (malloc_failed) *malloc_failed = 0; + /* the size is invalid if it is smaller than the number of * elements already inside the hash table */ if (dictIsRehashing(d) || d->ht[0].used > size) @@ -160,7 +164,14 @@ int dictExpand(dict *d, unsigned long size) /* Allocate the new hash table and initialize all pointers to NULL */ n.size = realsize; n.sizemask = realsize-1; - n.table = zcalloc(realsize*sizeof(dictEntry*)); + if (malloc_failed) { + n.table = ztrycalloc(realsize*sizeof(dictEntry*)); + *malloc_failed = n.table == NULL; + if (*malloc_failed) + return DICT_ERR; + } else + n.table = zcalloc(realsize*sizeof(dictEntry*)); + n.used = 0; /* Is this the first initialization? If so it's not really a rehashing @@ -176,6 +187,18 @@ int dictExpand(dict *d, unsigned long size) return DICT_OK; } +/* return DICT_ERR if expand was not performed */ +int dictExpand(dict *d, unsigned long size) { + return _dictExpand(d, size, NULL); +} + +/* return DICT_ERR if expand failed due to memory allocation failure */ +int dictTryExpand(dict *d, unsigned long size) { + int malloc_failed; + _dictExpand(d, size, &malloc_failed); + return malloc_failed? DICT_ERR : DICT_OK; +} + /* Performs N steps of incremental rehashing. Returns 1 if there are still * keys to move from the old to the new hash table, otherwise 0 is returned. * |