Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package redis for openSUSE:Factory checked in at 2023-01-18 13:08:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/redis (Old) and /work/SRC/openSUSE:Factory/.redis.new.32243 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "redis" Wed Jan 18 13:08:16 2023 rev:86 rq:1058816 version:7.0.8 Changes: -------- --- /work/SRC/openSUSE:Factory/redis/redis.changes 2022-12-20 20:20:04.621743431 +0100 +++ /work/SRC/openSUSE:Factory/.redis.new.32243/redis.changes 2023-01-18 13:08:20.743969982 +0100 @@ -1,0 +2,16 @@ +Mon Jan 16 21:00:00 UTC 2023 - Andreas Stieger <andreas.stie...@gmx.de> + +- redis 7.0.8 + * CVE-2022-35977: Integer overflow in the Redis SETRANGE and + SORT/SORT_RO commands can drive Redis to OOM panic boo#1207202 + * CVE-2023-22458: Integer overflow in the Redis HRANDFIELD and + ZRANDMEMBER commands can lead to denial-of-service boo#1207203 + * Avoid possible hang when client issues long KEYS, SRANDMEMBER, + HRANDFIELD, and ZRANDMEMBER commands and gets disconnected by + client output buffer limit + * Make sure that fork child doesn't do incremental rehashing + * Fix a bug where blocking commands with a sub-second timeout + would block forever + * Fix sentinel issue if replica changes IP + +------------------------------------------------------------------- Old: ---- redis-7.0.7.tar.gz New: ---- redis-7.0.8.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ redis.spec ++++++ --- /var/tmp/diff_new_pack.xenD8V/_old 2023-01-18 13:08:21.831975818 +0100 +++ /var/tmp/diff_new_pack.xenD8V/_new 2023-01-18 13:08:21.835975839 +0100 @@ -1,7 +1,7 @@ # # spec file for package redis # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -20,7 +20,7 @@ %define _log_dir %{_localstatedir}/log/%{name} %define _conf_dir %{_sysconfdir}/%{name} Name: redis -Version: 7.0.7 +Version: 7.0.8 Release: 0 Summary: Persistent key-value database License: BSD-3-Clause ++++++ redis-7.0.7.tar.gz -> redis-7.0.8.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/00-RELEASENOTES new/redis-7.0.8/00-RELEASENOTES --- old/redis-7.0.7/00-RELEASENOTES 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/00-RELEASENOTES 2023-01-16 17:40:35.000000000 +0100 @@ -12,6 +12,27 @@ -------------------------------------------------------------------------------- ================================================================================ +Redis 7.0.8 Released Mon Jan 16 12:00:00 IDT 2023 +================================================================================ + +Upgrade urgency: SECURITY, contains fixes to security issues. + +Security Fixes: +* (CVE-2022-35977) Integer overflow in the Redis SETRANGE and SORT/SORT_RO + commands can drive Redis to OOM panic +* (CVE-2023-22458) Integer overflow in the Redis HRANDFIELD and ZRANDMEMBER + commands can lead to denial-of-service + +Bug Fixes +========= + +* Avoid possible hang when client issues long KEYS, SRANDMEMBER, HRANDFIELD, + and ZRANDMEMBER commands and gets disconnected by client output buffer limit (#11676) +* Make sure that fork child doesn't do incremental rehashing (#11692) +* Fix a bug where blocking commands with a sub-second timeout would block forever (#11688) +* Fix sentinel issue if replica changes IP (#11590) + +================================================================================ Redis 7.0.7 Released Fri Dec 16 12:00:00 IST 2022 ================================================================================ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/commands/xsetid.json new/redis-7.0.8/src/commands/xsetid.json --- old/redis-7.0.7/src/commands/xsetid.json 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/commands/xsetid.json 2023-01-16 17:40:35.000000000 +0100 @@ -54,13 +54,15 @@ "name": "entries_added", "token": "ENTRIESADDED", "type": "integer", - "optional": true + "optional": true, + "since": "7.0.0" }, { "name": "max_deleted_entry_id", "token": "MAXDELETEDID", "type": "string", - "optional": true + "optional": true, + "since": "7.0.0" } ] } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/commands.c new/redis-7.0.8/src/commands.c --- old/redis-7.0.7/src/commands.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/commands.c 2023-01-16 17:40:35.000000000 +0100 @@ -6649,8 +6649,8 @@ struct redisCommandArg XSETID_Args[] = { {"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE}, {"last-id",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, -{"entries_added",ARG_TYPE_INTEGER,-1,"ENTRIESADDED",NULL,NULL,CMD_ARG_OPTIONAL}, -{"max_deleted_entry_id",ARG_TYPE_STRING,-1,"MAXDELETEDID",NULL,NULL,CMD_ARG_OPTIONAL}, +{"entries_added",ARG_TYPE_INTEGER,-1,"ENTRIESADDED",NULL,"7.0.0",CMD_ARG_OPTIONAL}, +{"max_deleted_entry_id",ARG_TYPE_STRING,-1,"MAXDELETEDID",NULL,"7.0.0",CMD_ARG_OPTIONAL}, {0} }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/db.c new/redis-7.0.8/src/db.c --- old/redis-7.0.7/src/db.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/db.c 2023-01-16 17:40:35.000000000 +0100 @@ -757,6 +757,8 @@ } decrRefCount(keyobj); } + if (c->flags & CLIENT_CLOSE_ASAP) + break; } dictReleaseIterator(di); setDeferredArrayLen(c,replylen,numkeys); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/dict.c new/redis-7.0.8/src/dict.c --- old/redis-7.0.7/src/dict.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/dict.c 2023-01-16 17:40:35.000000000 +0100 @@ -47,15 +47,15 @@ #include "zmalloc.h" #include "redisassert.h" -/* Using dictEnableResize() / dictDisableResize() we make possible to - * enable/disable resizing of the hash table as needed. This is very important +/* Using dictEnableResize() / dictDisableResize() we make possible to disable + * resizing and rehashing of the hash table as needed. This is very important * for Redis, as we use copy-on-write and don't want to move too much memory * around when there is a child performing saving operations. * * Note that even when dict_can_resize is set to 0, not all resizes are * prevented: a hash table is still allowed to grow if the ratio between * the number of elements and the buckets > dict_force_resize_ratio. */ -static int dict_can_resize = 1; +static dictResizeEnable dict_can_resize = DICT_RESIZE_ENABLE; static unsigned int dict_force_resize_ratio = 5; /* -------------------------- private prototypes ---------------------------- */ @@ -127,7 +127,7 @@ { unsigned long minimal; - if (!dict_can_resize || dictIsRehashing(d)) return DICT_ERR; + if (dict_can_resize != DICT_RESIZE_ENABLE || dictIsRehashing(d)) return DICT_ERR; minimal = d->ht_used[0]; if (minimal < DICT_HT_INITIAL_SIZE) minimal = DICT_HT_INITIAL_SIZE; @@ -210,7 +210,12 @@ * work it does would be unbound and the function may block for a long time. */ int dictRehash(dict *d, int n) { int empty_visits = n*10; /* Max number of empty buckets to visit. */ - if (!dictIsRehashing(d)) return 0; + if (dict_can_resize == DICT_RESIZE_FORBID || !dictIsRehashing(d)) return 0; + if (dict_can_resize == DICT_RESIZE_AVOID && + (DICTHT_SIZE(d->ht_size_exp[1]) / DICTHT_SIZE(d->ht_size_exp[0]) < dict_force_resize_ratio)) + { + return 0; + } while(n-- && d->ht_used[0] != 0) { dictEntry *de, *nextde; @@ -1000,10 +1005,12 @@ * table (global setting) or we should avoid it but the ratio between * elements/buckets is over the "safe" threshold, we resize doubling * the number of buckets. */ - if (d->ht_used[0] >= DICTHT_SIZE(d->ht_size_exp[0]) && - (dict_can_resize || - d->ht_used[0]/ DICTHT_SIZE(d->ht_size_exp[0]) > dict_force_resize_ratio) && - dictTypeExpandAllowed(d)) + if (!dictTypeExpandAllowed(d)) + return DICT_OK; + if ((dict_can_resize == DICT_RESIZE_ENABLE && + d->ht_used[0] >= DICTHT_SIZE(d->ht_size_exp[0])) || + (dict_can_resize != DICT_RESIZE_FORBID && + d->ht_used[0] / DICTHT_SIZE(d->ht_size_exp[0]) > dict_force_resize_ratio)) { return dictExpand(d, d->ht_used[0] + 1); } @@ -1063,12 +1070,8 @@ d->pauserehash = 0; } -void dictEnableResize(void) { - dict_can_resize = 1; -} - -void dictDisableResize(void) { - dict_can_resize = 0; +void dictSetResizeEnabled(dictResizeEnable enable) { + dict_can_resize = enable; } uint64_t dictGetHash(dict *d, const void *key) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/dict.h new/redis-7.0.8/src/dict.h --- old/redis-7.0.7/src/dict.h 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/dict.h 2023-01-16 17:40:35.000000000 +0100 @@ -169,6 +169,12 @@ #define randomULong() random() #endif +typedef enum { + DICT_RESIZE_ENABLE, + DICT_RESIZE_AVOID, + DICT_RESIZE_FORBID, +} dictResizeEnable; + /* API */ dict *dictCreate(dictType *type); int dictExpand(dict *d, unsigned long size); @@ -195,8 +201,7 @@ uint64_t dictGenHashFunction(const void *key, size_t len); uint64_t dictGenCaseHashFunction(const unsigned char *buf, size_t len); void dictEmpty(dict *d, void(callback)(dict*)); -void dictEnableResize(void); -void dictDisableResize(void); +void dictSetResizeEnabled(dictResizeEnable enable); int dictRehash(dict *d, int n); int dictRehashMilliseconds(dict *d, int ms); void dictSetHashFunctionSeed(uint8_t *seed); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/module.c new/redis-7.0.8/src/module.c --- old/redis-7.0.7/src/module.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/module.c 2023-01-16 17:40:35.000000000 +0100 @@ -322,6 +322,7 @@ typedef struct RedisModuleCommandFilterCtx { RedisModuleString **argv; + int argv_len; int argc; } RedisModuleCommandFilterCtx; @@ -9843,6 +9844,7 @@ RedisModuleCommandFilterCtx filter = { .argv = c->argv, + .argv_len = c->argv_len, .argc = c->argc }; @@ -9859,6 +9861,7 @@ } c->argv = filter.argv; + c->argv_len = filter.argv_len; c->argc = filter.argc; } @@ -9890,7 +9893,10 @@ if (pos < 0 || pos > fctx->argc) return REDISMODULE_ERR; - fctx->argv = zrealloc(fctx->argv, (fctx->argc+1)*sizeof(RedisModuleString *)); + if (fctx->argv_len < fctx->argc+1) { + fctx->argv_len = fctx->argc+1; + fctx->argv = zrealloc(fctx->argv, fctx->argv_len*sizeof(RedisModuleString *)); + } for (i = fctx->argc; i > pos; i--) { fctx->argv[i] = fctx->argv[i-1]; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/replication.c new/redis-7.0.8/src/replication.c --- old/redis-7.0.7/src/replication.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/replication.c 2023-01-16 17:40:35.000000000 +0100 @@ -585,7 +585,6 @@ while((ln = listNext(&li))) { client *monitor = ln->value; addReply(monitor,cmdobj); - updateClientMemUsageAndBucket(c); } decrRefCount(cmdobj); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/script_lua.c new/redis-7.0.8/src/script_lua.c --- old/redis-7.0.7/src/script_lua.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/script_lua.c 2023-01-16 17:40:35.000000000 +0100 @@ -781,7 +781,7 @@ /* --------------------------------------------------------------------------- * Lua redis.* functions implementations. * ------------------------------------------------------------------------- */ -void freeLuaRedisArgv(robj **argv, int argc); +void freeLuaRedisArgv(robj **argv, int argc, int argv_len); /* Cached argv array across calls. */ static robj **lua_argv = NULL; @@ -793,7 +793,7 @@ static robj *lua_args_cached_objects[LUA_CMD_OBJCACHE_SIZE]; static size_t lua_args_cached_objects_len[LUA_CMD_OBJCACHE_SIZE]; -static robj **luaArgsToRedisArgv(lua_State *lua, int *argc) { +static robj **luaArgsToRedisArgv(lua_State *lua, int *argc, int *argv_len) { int j; /* Require at least one argument */ *argc = lua_gettop(lua); @@ -807,6 +807,7 @@ lua_argv = zrealloc(lua_argv,sizeof(robj*)* *argc); lua_argv_size = *argc; } + *argv_len = lua_argv_size; for (j = 0; j < *argc; j++) { char *obj_s; @@ -846,7 +847,7 @@ * is not a string or an integer (lua_isstring() return true for * integers as well). */ if (j != *argc) { - freeLuaRedisArgv(lua_argv, j); + freeLuaRedisArgv(lua_argv, j, lua_argv_size); luaPushError(lua, "Lua redis lib command arguments must be strings or integers"); return NULL; } @@ -854,7 +855,7 @@ return lua_argv; } -void freeLuaRedisArgv(robj **argv, int argc) { +void freeLuaRedisArgv(robj **argv, int argc, int argv_len) { int j; for (j = 0; j < argc; j++) { robj *o = argv[j]; @@ -876,7 +877,7 @@ decrRefCount(o); } } - if (argv != lua_argv) { + if (argv != lua_argv || argv_len != lua_argv_size) { /* The command changed argv, scrap the cache and start over. */ zfree(argv); lua_argv = NULL; @@ -895,8 +896,7 @@ client* c = rctx->c; sds reply; - c->argv = luaArgsToRedisArgv(lua, &c->argc); - c->argv_len = lua_argv_size; + c->argv = luaArgsToRedisArgv(lua, &c->argc, &c->argv_len); if (c->argv == NULL) { return raise_error ? luaError(lua) : 1; } @@ -978,7 +978,7 @@ cleanup: /* Clean up. Command code may have changed argv/argc so we use the * argv/argc of the client instead of the local variables. */ - freeLuaRedisArgv(c->argv, c->argc); + freeLuaRedisArgv(c->argv, c->argc, c->argv_len); c->argc = c->argv_len = 0; c->user = NULL; c->argv = NULL; @@ -1135,8 +1135,8 @@ } int raise_error = 0; - int argc; - robj **argv = luaArgsToRedisArgv(lua, &argc); + int argc, argv_len; + robj **argv = luaArgsToRedisArgv(lua, &argc, &argv_len); /* Require at least one argument */ if (argv == NULL) return luaError(lua); @@ -1155,7 +1155,7 @@ } } - freeLuaRedisArgv(argv, argc); + freeLuaRedisArgv(argv, argc, argv_len); if (raise_error) return luaError(lua); else diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/sentinel.c new/redis-7.0.8/src/sentinel.c --- old/redis-7.0.7/src/sentinel.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/sentinel.c 2023-01-16 17:40:35.000000000 +0100 @@ -598,11 +598,6 @@ zfree(sa); } -/* Return non-zero if two addresses are equal. */ -int sentinelAddrIsEqual(sentinelAddr *a, sentinelAddr *b) { - return a->port == b->port && !strcasecmp(a->ip,b->ip); -} - /* Return non-zero if the two addresses are equal, either by address * or by hostname if they could not have been resolved. */ @@ -1616,7 +1611,7 @@ while((de = dictNext(di)) != NULL) { sentinelRedisInstance *slave = dictGetVal(de); - if (sentinelAddrIsEqual(slave->addr,newaddr)) continue; + if (sentinelAddrOrHostnameEqual(slave->addr,newaddr)) continue; slaves[numslaves++] = dupSentinelAddr(slave->addr); } dictReleaseIterator(di); @@ -1624,7 +1619,7 @@ /* If we are switching to a different address, include the old address * as a slave as well, so that we'll be able to sense / reconfigure * the old master. */ - if (!sentinelAddrIsEqual(newaddr,master->addr)) { + if (!sentinelAddrOrHostnameEqual(newaddr,master->addr)) { slaves[numslaves++] = dupSentinelAddr(master->addr); } @@ -2175,7 +2170,7 @@ * slave's address, a failover is in progress and the slave was * already successfully promoted. So as the address of this slave * we use the old master address instead. */ - if (sentinelAddrIsEqual(slave_addr,master_addr)) + if (sentinelAddrOrHostnameEqual(slave_addr,master_addr)) slave_addr = master->addr; line = sdscatprintf(sdsempty(), "sentinel known-replica %s %s %d", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/server.c new/redis-7.0.8/src/server.c --- old/redis-7.0.7/src/server.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/server.c 2023-01-16 17:40:35.000000000 +0100 @@ -594,13 +594,15 @@ * as we want to avoid resizing the hash tables when there is a child in order * to play well with copy-on-write (otherwise when a resize happens lots of * memory pages are copied). The goal of this function is to update the ability - * for dict.c to resize the hash tables accordingly to the fact we have an + * for dict.c to resize or rehash the tables accordingly to the fact we have an * active fork child running. */ void updateDictResizePolicy(void) { - if (!hasActiveChildProcess()) - dictEnableResize(); + if (server.in_fork_child != CHILD_TYPE_NONE) + dictSetResizeEnabled(DICT_RESIZE_FORBID); + else if (hasActiveChildProcess()) + dictSetResizeEnabled(DICT_RESIZE_AVOID); else - dictDisableResize(); + dictSetResizeEnabled(DICT_RESIZE_ENABLE); } const char *strChildType(int type) { @@ -873,6 +875,12 @@ * together clients consuming about the same amount of memory and can quickly * free them in case we reach maxmemory-clients (client eviction). * + * Note: This function filters clients of type monitor, master or replica regardless + * of whether the eviction is enabled or not, so the memory usage we get from these + * types of clients via the INFO command may be out of date. If someday we wanna + * improve that to make monitors' memory usage more accurate, we need to re-add this + * function call to `replicationFeedMonitors()`. + * * returns 1 if client eviction for this client is allowed, 0 otherwise. */ int updateClientMemUsageAndBucket(client *c) { @@ -6411,6 +6419,7 @@ server.in_fork_child = purpose; setupChildSignalHandlers(); setOOMScoreAdj(CONFIG_OOM_BGCHILD); + updateDictResizePolicy(); dismissMemoryInChild(); closeChildUnusedResourceAfterFork(); /* Close the reading part, so that if the parent crashes, the child will diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/sort.c new/redis-7.0.8/src/sort.c --- old/redis-7.0.7/src/sort.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/sort.c 2023-01-16 17:40:35.000000000 +0100 @@ -328,8 +328,10 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/t_hash.c new/redis-7.0.8/src/t_hash.c --- old/redis-7.0.7/src/t_hash.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/t_hash.c 2023-01-16 17:40:35.000000000 +0100 @@ -956,6 +956,8 @@ addReplyBulkCBuffer(c, key, sdslen(key)); if (withvalues) addReplyBulkCBuffer(c, value, sdslen(value)); + if (c->flags & CLIENT_CLOSE_ASAP) + break; } } else if (hash->encoding == OBJ_ENCODING_LISTPACK) { listpackEntry *keys, *vals = NULL; @@ -970,6 +972,8 @@ count -= sample_count; lpRandomPairs(hash->ptr, sample_count, keys, vals); hrandfieldReplyWithListpack(c, sample_count, keys, vals); + if (c->flags & CLIENT_CLOSE_ASAP) + break; } zfree(keys); zfree(vals); @@ -1120,8 +1124,13 @@ if (c->argc > 4 || (c->argc == 4 && strcasecmp(c->argv[3]->ptr,"withvalues"))) { addReplyErrorObject(c,shared.syntaxerr); return; - } else if (c->argc == 4) + } else if (c->argc == 4) { withvalues = 1; + if (l < LONG_MIN/2 || l > LONG_MAX/2) { + addReplyError(c,"value is out of range"); + return; + } + } hrandfieldWithCountCommand(c, l, withvalues); return; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/t_set.c new/redis-7.0.8/src/t_set.c --- old/redis-7.0.7/src/t_set.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/t_set.c 2023-01-16 17:40:35.000000000 +0100 @@ -699,6 +699,8 @@ } else { addReplyBulkCBuffer(c,ele,sdslen(ele)); } + if (c->flags & CLIENT_CLOSE_ASAP) + break; } return; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/t_string.c new/redis-7.0.8/src/t_string.c --- old/redis-7.0.7/src/t_string.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/t_string.c 2023-01-16 17:40:35.000000000 +0100 @@ -37,8 +37,14 @@ * 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; } @@ -456,7 +462,7 @@ } /* 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))); @@ -476,7 +482,7 @@ } /* 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. */ @@ -555,6 +561,7 @@ void msetGenericCommand(client *c, int nx) { int j; + int setkey_flags = 0; if ((c->argc % 2) == 0) { addReplyErrorArity(c); @@ -570,11 +577,12 @@ return; } } + setkey_flags |= SETKEY_DOESNT_EXIST; } for (j = 1; j < c->argc; j += 2) { c->argv[j+1] = tryObjectEncoding(c->argv[j+1]); - setKey(c,c->db,c->argv[j],c->argv[j+1],0); + setKey(c, c->db, c->argv[j], c->argv[j + 1], setkey_flags); notifyKeyspaceEvent(NOTIFY_STRING,"set",c->argv[j],c->db->id); } server.dirty += (c->argc-1)/2; @@ -703,8 +711,7 @@ /* "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 */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/t_zset.c new/redis-7.0.8/src/t_zset.c --- old/redis-7.0.7/src/t_zset.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/t_zset.c 2023-01-16 17:40:35.000000000 +0100 @@ -4126,6 +4126,8 @@ addReplyBulkCBuffer(c, key, sdslen(key)); if (withscores) addReplyDouble(c, *(double*)dictGetVal(de)); + if (c->flags & CLIENT_CLOSE_ASAP) + break; } } else if (zsetobj->encoding == OBJ_ENCODING_LISTPACK) { listpackEntry *keys, *vals = NULL; @@ -4139,6 +4141,8 @@ count -= sample_count; lpRandomPairs(zsetobj->ptr, sample_count, keys, vals); zrandmemberReplyWithListpack(c, sample_count, keys, vals); + if (c->flags & CLIENT_CLOSE_ASAP) + break; } zfree(keys); zfree(vals); @@ -4289,8 +4293,13 @@ if (c->argc > 4 || (c->argc == 4 && strcasecmp(c->argv[3]->ptr,"withscores"))) { addReplyErrorObject(c,shared.syntaxerr); return; - } else if (c->argc == 4) + } else if (c->argc == 4) { withscores = 1; + if (l < LONG_MIN/2 || l > LONG_MAX/2) { + addReplyError(c,"value is out of range"); + return; + } + } zrandmemberWithCountCommand(c, l, withscores); return; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/timeout.c new/redis-7.0.8/src/timeout.c --- old/redis-7.0.7/src/timeout.c 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/timeout.c 2023-01-16 17:40:35.000000000 +0100 @@ -29,6 +29,8 @@ #include "server.h" #include "cluster.h" +#include <math.h> + /* ========================== Clients timeouts ============================= */ /* Check if this blocked client timedout (does nothing if the client is @@ -169,7 +171,7 @@ if (getLongDoubleFromObjectOrReply(c,object,&ftval, "timeout is not a float or out of range") != C_OK) return C_ERR; - tval = (long long) (ftval * 1000.0); + tval = (long long) ceill(ftval * 1000.0); } else { if (getLongLongFromObjectOrReply(c,object,&tval, "timeout is not an integer or out of range") != C_OK) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/src/version.h new/redis-7.0.8/src/version.h --- old/redis-7.0.7/src/version.h 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/src/version.h 2023-01-16 17:40:35.000000000 +0100 @@ -1,2 +1,2 @@ -#define REDIS_VERSION "7.0.7" -#define REDIS_VERSION_NUM 0x00070007 +#define REDIS_VERSION "7.0.8" +#define REDIS_VERSION_NUM 0x00070008 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/tests/unit/moduleapi/commandfilter.tcl new/redis-7.0.8/tests/unit/moduleapi/commandfilter.tcl --- old/redis-7.0.7/tests/unit/moduleapi/commandfilter.tcl 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/tests/unit/moduleapi/commandfilter.tcl 2023-01-16 17:40:35.000000000 +0100 @@ -96,3 +96,23 @@ assert_equal {OK} [r module unload commandfilter] } } + +test {RM_CommandFilterArgInsert and script argv caching} { + # coverage for scripts calling commands that expand the argv array + # an attempt to add coverage for a possible bug in luaArgsToRedisArgv + # this test needs a fresh server so that lua_argv_size is 0. + # glibc realloc can return the same pointer even when the size changes + # still this test isn't able to trigger the issue, but we keep it anyway. + start_server {tags {"modules"}} { + r module load $testmodule log-key 0 + r del mylist + # command with 6 args + r eval {redis.call('rpush', KEYS[1], 'elem1', 'elem2', 'elem3', 'elem4')} 1 mylist + # command with 3 args that is changed to 4 + r eval {redis.call('rpush', KEYS[1], '@insertafter')} 1 mylist + # command with 6 args again + r eval {redis.call('rpush', KEYS[1], 'elem1', 'elem2', 'elem3', 'elem4')} 1 mylist + assert_equal [r lrange mylist 0 -1] {elem1 elem2 elem3 elem4 @insertafter --inserted-after-- elem1 elem2 elem3 elem4} + } +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/tests/unit/obuf-limits.tcl new/redis-7.0.8/tests/unit/obuf-limits.tcl --- old/redis-7.0.7/tests/unit/obuf-limits.tcl 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/tests/unit/obuf-limits.tcl 2023-01-16 17:40:35.000000000 +0100 @@ -211,4 +211,20 @@ assert_equal "v2" [r get k2] assert_equal "v3" [r get k3] } + + test "Obuf limit, HRANDFIELD with huge count stopped mid-run" { + r config set client-output-buffer-limit {normal 1000000 0 0} + r hset myhash a b + catch {r hrandfield myhash -999999999} e + assert_match "*I/O error*" $e + reconnect + } + + test "Obuf limit, KEYS stopped mid-run" { + r config set client-output-buffer-limit {normal 100000 0 0} + populate 1000 "long-key-name-prefix-of-100-chars-------------------------------------------------------------------" + catch {r keys *} e + assert_match "*I/O error*" $e + reconnect + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/tests/unit/scripting.tcl new/redis-7.0.8/tests/unit/scripting.tcl --- old/redis-7.0.7/tests/unit/scripting.tcl 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/tests/unit/scripting.tcl 2023-01-16 17:40:35.000000000 +0100 @@ -585,6 +585,30 @@ close_replication_stream $repl } {} {needs:repl} + test {INCRBYFLOAT: We can call scripts expanding client->argv from Lua} { + # coverage for scripts calling commands that expand the argv array + # an attempt to add coverage for a possible bug in luaArgsToRedisArgv + # this test needs a fresh server so that lua_argv_size is 0. + # glibc realloc can return the same pointer even when the size changes + # still this test isn't able to trigger the issue, but we keep it anyway. + start_server {tags {"scripting"}} { + set repl [attach_to_replication_stream] + # a command with 5 argsument + r eval {redis.call('hmget', KEYS[1], 1, 2, 3)} 1 key + # then a command with 3 that is replicated as one with 4 + r eval {redis.call('incrbyfloat', KEYS[1], 1)} 1 key + # then a command with 4 args + r eval {redis.call('set', KEYS[1], '1', 'KEEPTTL')} 1 key + + assert_replication_stream $repl { + {select *} + {set key 1 KEEPTTL} + {set key 1 KEEPTTL} + } + close_replication_stream $repl + } + } {} {needs:repl} + } ;# is_eval test {Call Redis command with many args from Lua (issue #1764)} { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/tests/unit/sort.tcl new/redis-7.0.8/tests/unit/sort.tcl --- old/redis-7.0.7/tests/unit/sort.tcl 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/tests/unit/sort.tcl 2023-01-16 17:40:35.000000000 +0100 @@ -327,4 +327,15 @@ } } {} {cluster:skip} } + + test {SETRANGE with huge offset} { + r lpush L 2 1 0 + # expecting a different outcome on 32 and 64 bit systems + foreach value {9223372036854775807 2147483647} { + catch {[r sort_ro L by a limit 2 $value]} res + if {![string match "2" $res] && ![string match "*out of range*" $res]} { + assert_not_equal $res "expecting an error or 2" + } + } + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/tests/unit/type/hash.tcl new/redis-7.0.8/tests/unit/type/hash.tcl --- old/redis-7.0.7/tests/unit/type/hash.tcl 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/tests/unit/type/hash.tcl 2023-01-16 17:40:35.000000000 +0100 @@ -71,6 +71,11 @@ r hrandfield myhash 0 } {} + test "HRANDFIELD count overflow" { + r hmset myhash a 1 + assert_error {*value is out of range*} {r hrandfield myhash -9223372036854770000 withvalues} + } {} + test "HRANDFIELD with <count> against non existing key" { r hrandfield nonexisting_key 100 } {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/tests/unit/type/list.tcl new/redis-7.0.8/tests/unit/type/list.tcl --- old/redis-7.0.7/tests/unit/type/list.tcl 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/tests/unit/type/list.tcl 2023-01-16 17:40:35.000000000 +0100 @@ -1256,6 +1256,16 @@ $rd close } + test "$pop: with 0.001 timeout should not block indefinitely" { + # Use a timeout of 0.001 and wait for the number of blocked clients to equal 0. + # Validate the empty read from the deferring client. + set rd [redis_deferring_client] + bpop_command $rd $pop blist1 0.001 + wait_for_blocked_clients_count 0 + assert_equal {} [$rd read] + $rd close + } + test "$pop: second argument is not a list" { set rd [redis_deferring_client] r del blist1{t} blist2{t} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/tests/unit/type/string.tcl new/redis-7.0.8/tests/unit/type/string.tcl --- old/redis-7.0.7/tests/unit/type/string.tcl 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/tests/unit/type/string.tcl 2023-01-16 17:40:35.000000000 +0100 @@ -598,4 +598,14 @@ test {LCS indexes with match len and minimum match len} { dict get [r LCS virus1{t} virus2{t} IDX WITHMATCHLEN MINMATCHLEN 5] matches } {{{1 222} {13 234} 222}} + + test {SETRANGE with huge offset} { + foreach value {9223372036854775807 2147483647} { + catch {[r setrange K $value A]} res + # expecting a different error on 32 and 64 bit systems + if {![string match "*string exceeds maximum allowed size*" $res] && ![string match "*out of range*" $res]} { + assert_equal $res "expecting an error" + } + } + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-7.0.7/tests/unit/type/zset.tcl new/redis-7.0.8/tests/unit/type/zset.tcl --- old/redis-7.0.7/tests/unit/type/zset.tcl 2022-12-16 11:52:57.000000000 +0100 +++ new/redis-7.0.8/tests/unit/type/zset.tcl 2023-01-16 17:40:35.000000000 +0100 @@ -2300,6 +2300,11 @@ r zrandmember nonexisting_key 100 } {} + test "ZRANDMEMBER count overflow" { + r zadd myzset 0 a + assert_error {*value is out of range*} {r zrandmember myzset -9223372036854770000 withscores} + } {} + # Make sure we can distinguish between an empty array and a null response r readraw 1 ++++++ redis.hashes ++++++ --- /var/tmp/diff_new_pack.xenD8V/_old 2023-01-18 13:08:22.443979100 +0100 +++ /var/tmp/diff_new_pack.xenD8V/_new 2023-01-18 13:08:22.447979122 +0100 @@ -146,4 +146,6 @@ hash redis-6.2.8.tar.gz sha256 f91ab24bcb42673cb853292eb5d43c2017d11d659854808ed6a529c97297fdfe http://download.redis.io/releases/redis-6.2.8.tar.gz hash redis-7.0.6.tar.gz sha256 7b33a7e890d13e27af1f246acb16312669ad8a1d56ce8f807dfbcd3c09aa7bb3 http://download.redis.io/releases/redis-7.0.6.tar.gz hash redis-7.0.7.tar.gz sha256 8d327d7e887d1bb308fc37aaf717a0bf79f58129e3739069aaeeae88955ac586 http://download.redis.io/releases/redis-7.0.7.tar.gz +hash redis-7.0.8.tar.gz sha256 06a339e491306783dcf55b97f15a5dbcbdc01ccbde6dc23027c475cab735e914 http://download.redis.io/releases/redis-7.0.8.tar.gz +hash redis-6.2.9.tar.gz sha256 9661b2c6b1cc9bf2999471b37a4d759fa5e747d408142c18af8792ebd8384a2a http://download.redis.io/releases/redis-6.2.9.tar.gz