Sanitize dump payload: fix empty keys when RDB loading and restore command#9297
Sanitize dump payload: fix empty keys when RDB loading and restore command#9297oranagra merged 9 commits intoredis:unstablefrom
Conversation
|
@sundb i'm thinking that maybe we'll have to revert some of these checks in rdb.c. I suppose this batch of changes in rdb.c came up after you encountered an issue in the fuzzer that lead to adding the new |
|
@oranagra I remember there were Module API bugs that could result with that, and there were reports about that happening in the wild. Do you see harm in simply skipping those keys? |
|
@yossigo i guess not... if we have to choose between failing the loading, storing an empty key in the db, or skipping it, i suppose skipping it is the better alternative. i.e. specifically because we had that bug. |
|
@sundb i looked at the recent failures in the daily CI, i see they're all about several lists commands.
and others reach ziplist sanitation errors:
the reason the test suite failed is because when or maybe we should do that only for zsets (have that check depend on the |
|
@yossigo i think i'd like to propose the following:
|
restore key 0 "\x0E\xC0\x2B\x15\x00\x00\x00\x0A\x00\x00\x00\x01\x00\x00\xE0\x62\x58\xEA\xDF\x22\x00\x00\x00\xFF\x09\x00\xDF\x35\xD2\x67\xDC\x0E\x89\xAB" replace
lpop key
config set sanitize-dump-payload yes
debug set-skip-checksum-validation 1
restore key 0 "\x0E\x01\x11\x11\x00\x00\x00\x0A\x00\x00\x00\x01\x00\x00\xF6\xFF\xB0\x6C\x9C\xFF\x09\x00\x9C\x37\x47\x49\x4D\xDE\x94\xF5" replace
RPUSH key 1
RPOP key
RPOP key
|
|
@oranagra Can you think of a reason not to apply it to all types (and maybe keep a counter of such keys and report it in the log so it will not go unnoticed)? I think it's a bit cleaner to make this more generic and not a workaround for a specific known bug (in the future we could learn of similar bugs affecting other types). |
|
@yossigo ok, so you say that we should assume we may have had similar issues like the zset one on other types. |
…etZiplistValidateIntegrity
|
@oranagra Per our discussion, I think that last note makes sense. |
src/rdb.c
Outdated
| /* Don't fail when empty key is encountered, we will | ||
| * silently discard it and continue loading. */ | ||
| if (error == RDB_LOAD_ERR_EMPTY_KEY) | ||
| continue; |
There was a problem hiding this comment.
when we continue here, we're skipping this block:
/* Reset the state that is key-specified and is populated by
* opcodes before the key, so that we start from scratch again. */
expiretime = -1;
lfu_freq = -1;
lru_idle = -1;maybe a cleaner idea is to add a first if to the if-else chain below, so that all the other ifs will not be taken. then similarly to an already expired key, we continue with the normal flow of this loop.
also, let's mention #8453 in the comment to justify why we do that.
There was a problem hiding this comment.
Yes, I am building this rdb file.
Co-authored-by: Oran Agra <[email protected]>
yossigo
left a comment
There was a problem hiding this comment.
LGTM, one real comment (about the logging) and a minor style nit.
src/rdb.c
Outdated
| * in an RDB file, instead we will silently discard it and | ||
| * continue loading. */ | ||
| if (error == RDB_LOAD_ERR_EMPTY_KEY) { | ||
| serverLog(LL_WARNING, "rdbLoadObject failed, detect empty key: %s", key); |
There was a problem hiding this comment.
I think it's better to set a counter and maybe report the first occurrence and later the number of total such keys. A log message per key can be devastating for the log file...
There was a problem hiding this comment.
It bothered me too, but I didn't want to lower the log level.
Yossi's idea seems best
Recently we found two issues in the fuzzer tester: #9302 #9285 After fixing them, more problems surfaced and this PR (as well as #9297) aims to fix them. Here's a list of the fixes - Prevent an overflow when allocating a dict hashtable - Prevent OOM when attempting to allocate a huge string - Prevent a few invalid accesses in listpack - Improve sanitization of listpack first entry - Validate integrity of stream consumer groups PEL - Validate integrity of stream listpack entry IDs - Validate ziplist tail followed by extra data which start with 0xff Co-authored-by: sundb <[email protected]>
1) Fix CR 2) In resolving conflict, I reverted all corrupt-test tests, as some were fixed in redis#9302, and Re-add the new issue caused this pr. 3) ziplistValidateIntegrity fails to validate an empty ziplsit because hash ziplist->listpack conversion is always deep santization, this should be fixed in redis#9297 but was missed.
…d restore command (#9349) This commit mainly fixes empty keys due to RDB loading and restore command, which was omitted in #9297. 1) When loading quicklsit, if all the ziplists in the quicklist are empty, NULL will be returned. If only some of the ziplists are empty, then we will skip the empty ziplists silently. 2) When loading hash zipmap, if zipmap is empty, sanitization check will fail. 3) When loading hash ziplist, if ziplist is empty, NULL will be returned. 4) Add RDB loading test with sanitize.
…mmand (redis#9297) When we load rdb or restore command, if we encounter a length of 0, it will result in the creation of an empty key. This could either be a corrupt payload, or a result of a bug (see redis#8453 ) This PR mainly fixes the following: 1) When restore command will return `Bad data format` error. 2) When loading RDB, we will silently discard the key. Co-authored-by: Oran Agra <[email protected]>
Recently we found two issues in the fuzzer tester: redis#9302 redis#9285 After fixing them, more problems surfaced and this PR (as well as redis#9297) aims to fix them. Here's a list of the fixes - Prevent an overflow when allocating a dict hashtable - Prevent OOM when attempting to allocate a huge string - Prevent a few invalid accesses in listpack - Improve sanitization of listpack first entry - Validate integrity of stream consumer groups PEL - Validate integrity of stream listpack entry IDs - Validate ziplist tail followed by extra data which start with 0xff Co-authored-by: sundb <[email protected]>
…d restore command (redis#9349) This commit mainly fixes empty keys due to RDB loading and restore command, which was omitted in redis#9297. 1) When loading quicklsit, if all the ziplists in the quicklist are empty, NULL will be returned. If only some of the ziplists are empty, then we will skip the empty ziplists silently. 2) When loading hash zipmap, if zipmap is empty, sanitization check will fail. 3) When loading hash ziplist, if ziplist is empty, NULL will be returned. 4) Add RDB loading test with sanitize.
…mmand (#9297) When we load rdb or restore command, if we encounter a length of 0, it will result in the creation of an empty key. This could either be a corrupt payload, or a result of a bug (see #8453 ) This PR mainly fixes the following: 1) When restore command will return `Bad data format` error. 2) When loading RDB, we will silently discard the key. Co-authored-by: Oran Agra <[email protected]> (cherry picked from commit 8ea777a)
Recently we found two issues in the fuzzer tester: #9302 #9285 After fixing them, more problems surfaced and this PR (as well as #9297) aims to fix them. Here's a list of the fixes - Prevent an overflow when allocating a dict hashtable - Prevent OOM when attempting to allocate a huge string - Prevent a few invalid accesses in listpack - Improve sanitization of listpack first entry - Validate integrity of stream consumer groups PEL - Validate integrity of stream listpack entry IDs - Validate ziplist tail followed by extra data which start with 0xff Co-authored-by: sundb <[email protected]> (cherry picked from commit 0c90370)
…d restore command (#9349) This commit mainly fixes empty keys due to RDB loading and restore command, which was omitted in #9297. 1) When loading quicklsit, if all the ziplists in the quicklist are empty, NULL will be returned. If only some of the ziplists are empty, then we will skip the empty ziplists silently. 2) When loading hash zipmap, if zipmap is empty, sanitization check will fail. 3) When loading hash ziplist, if ziplist is empty, NULL will be returned. 4) Add RDB loading test with sanitize. (cherry picked from commit cbda492)
#11519) The following example will create an empty set (listpack encoding): ``` > RESTORE key 0 "\x14\x25\x25\x00\x00\x00\x00\x00\x02\x01\x82\x5F\x37\x03\x06\x01\x82\x5F\x35\x03\x82\x5F\x33\x03\x00\x01\x82\x5F\x31\x03\x82\x5F\x39\x03\x04\xA9\x08\x01\xFF\x0B\x00\xA3\x26\x49\xB4\x86\xB0\x0F\x41" OK > SCARD key (integer) 0 > SRANDMEMBER key Error: Server closed the connection ``` In the spirit of #9297, skip empty set when loading RDB_TYPE_SET_LISTPACK. Introduced in #11290
redis#11519) The following example will create an empty set (listpack encoding): ``` > RESTORE key 0 "\x14\x25\x25\x00\x00\x00\x00\x00\x02\x01\x82\x5F\x37\x03\x06\x01\x82\x5F\x35\x03\x82\x5F\x33\x03\x00\x01\x82\x5F\x31\x03\x82\x5F\x39\x03\x04\xA9\x08\x01\xFF\x0B\x00\xA3\x26\x49\xB4\x86\xB0\x0F\x41" OK > SCARD key (integer) 0 > SRANDMEMBER key Error: Server closed the connection ``` In the spirit of redis#9297, skip empty set when loading RDB_TYPE_SET_LISTPACK. Introduced in redis#11290
redis#11519) The following example will create an empty set (listpack encoding): ``` > RESTORE key 0 "\x14\x25\x25\x00\x00\x00\x00\x00\x02\x01\x82\x5F\x37\x03\x06\x01\x82\x5F\x35\x03\x82\x5F\x33\x03\x00\x01\x82\x5F\x31\x03\x82\x5F\x39\x03\x04\xA9\x08\x01\xFF\x0B\x00\xA3\x26\x49\xB4\x86\xB0\x0F\x41" OK > SCARD key (integer) 0 > SRANDMEMBER key Error: Server closed the connection ``` In the spirit of redis#9297, skip empty set when loading RDB_TYPE_SET_LISTPACK. Introduced in redis#11290
When we load rdb or restore command, if we encounter a length of 0, it will result in the creation of an empty key.
This could either be a corrupt payload, or a result of a bug (see #8453 )
This pr mainly fixes the following:
Bad data formaterror.