Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package redis for openSUSE:Factory checked in at 2021-06-04 22:42:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/redis (Old) and /work/SRC/openSUSE:Factory/.redis.new.1898 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "redis" Fri Jun 4 22:42:32 2021 rev:71 rq:896856 version:6.2.4 Changes: -------- --- /work/SRC/openSUSE:Factory/redis/redis.changes 2021-06-01 10:32:50.416340953 +0200 +++ /work/SRC/openSUSE:Factory/.redis.new.1898/redis.changes 2021-06-04 22:42:38.079067781 +0200 @@ -1,0 +2,17 @@ +Wed Jun 2 07:57:17 UTC 2021 - Andreas Stieger <andreas.stie...@gmx.de> + +- redis 6.2.4: + * CVE-2021-32625: An integer overflow bug could be exploited by + using the STRALGO LCS command to cause remote remote code + execution (boo#1186722) + * Fix crash after a diskless replication fork child is terminated + * Fix redis-benchmark crash on unsupported configs + * Fix crash in UNLINK on a stream key with deleted consumer groups + * SINTERSTORE: Add missing keyspace del event when none of the + sources exist + * Sentinel: Fix CONFIG SET of empty string + sentinel-user/sentinel-pass configs + * Enforce client output buffer soft limit when no traffic + * Hide AUTH passwords in MIGRATE command from slowlog + +------------------------------------------------------------------- Old: ---- redis-6.2.3.tar.gz New: ---- redis-6.2.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ redis.spec ++++++ --- /var/tmp/diff_new_pack.GQ2NvC/_old 2021-06-04 22:42:38.947068739 +0200 +++ /var/tmp/diff_new_pack.GQ2NvC/_new 2021-06-04 22:42:38.947068739 +0200 @@ -20,7 +20,7 @@ %define _log_dir %{_localstatedir}/log/%{name} %define _conf_dir %{_sysconfdir}/%{name} Name: redis -Version: 6.2.3 +Version: 6.2.4 Release: 0 Summary: Persistent key-value database License: BSD-3-Clause ++++++ redis-6.2.3.tar.gz -> redis-6.2.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/00-RELEASENOTES new/redis-6.2.4/00-RELEASENOTES --- old/redis-6.2.3/00-RELEASENOTES 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/00-RELEASENOTES 2021-06-01 16:03:36.000000000 +0200 @@ -12,6 +12,31 @@ -------------------------------------------------------------------------------- ================================================================================ +Redis 6.2.4 Released Tue July 1 12:00:00 IST 2021 +================================================================================ + +Upgrade urgency: SECURITY, Contains fixes to security issues that affect +authenticated client connections. MODERATE otherwise. + +Fix integer overflow in STRALGO LCS (CVE-2021-32625) +An integer overflow bug in Redis version 6.0 or newer can be exploited using the +STRALGO LCS command to corrupt the heap and potentially result with remote code +execution. This is a result of an incomplete fix by CVE-2021-29477. + +Bug fixes that are only applicable to previous releases of Redis 6.2: +* Fix crash after a diskless replication fork child is terminated (#8991) +* Fix redis-benchmark crash on unsupported configs (#8916) + +Other bug fixes: +* Fix crash in UNLINK on a stream key with deleted consumer groups (#8932) +* SINTERSTORE: Add missing keyspace del event when none of the sources exist (#8949) +* Sentinel: Fix CONFIG SET of empty string sentinel-user/sentinel-pass configs (#8958) +* Enforce client output buffer soft limit when no traffic (#8833) + +Improvements: +* Hide AUTH passwords in MIGRATE command from slowlog (#8859) + +================================================================================ Redis 6.2.3 Released Mon May 3 19:00:00 IST 2021 ================================================================================ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/acl.c new/redis-6.2.4/src/acl.c --- old/redis-6.2.3/src/acl.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/acl.c 2021-06-01 16:03:36.000000000 +0200 @@ -1892,10 +1892,6 @@ void aclCommand(client *c) { char *sub = c->argv[1]->ptr; if (!strcasecmp(sub,"setuser") && c->argc >= 3) { - /* Consider information about passwords or permissions - * to be sensitive, which will be the arguments for this - * subcommand. */ - preventCommandLogging(c); sds username = c->argv[2]->ptr; /* Check username validity. */ if (ACLStringHasSpaces(username,sdslen(username))) { @@ -1912,6 +1908,12 @@ user *u = ACLGetUserByName(username,sdslen(username)); if (u) ACLCopyUser(tempu, u); + /* Initially redact all of the arguments to not leak any information + * about the user. */ + for (int j = 2; j < c->argc; j++) { + redactClientCommandArgument(c, j); + } + for (int j = 3; j < c->argc; j++) { if (ACLSetUser(tempu,c->argv[j]->ptr,sdslen(c->argv[j]->ptr)) != C_OK) { const char *errmsg = ACLSetUserStringError(); @@ -2245,6 +2247,8 @@ addReplyErrorObject(c,shared.syntaxerr); return; } + /* Always redact the second argument */ + redactClientCommandArgument(c, 1); /* Handle the two different forms here. The form with two arguments * will just use "default" as username. */ @@ -2264,6 +2268,7 @@ } else { username = c->argv[1]; password = c->argv[2]; + redactClientCommandArgument(c, 2); } if (ACLAuthenticateUser(c,username,password) == C_OK) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/childinfo.c new/redis-6.2.4/src/childinfo.c --- old/redis-6.2.3/src/childinfo.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/childinfo.c 2021-06-01 16:03:36.000000000 +0200 @@ -93,7 +93,7 @@ if (cow) { serverLog((info_type == CHILD_INFO_TYPE_CURRENT_INFO) ? LL_VERBOSE : LL_NOTICE, "%s: %zu MB of memory used by copy-on-write", - pname, data.cow / (1024 * 1024)); + pname, cow / (1024 * 1024)); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/cluster.c new/redis-6.2.4/src/cluster.c --- old/redis-6.2.3/src/cluster.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/cluster.c 2021-06-01 16:03:36.000000000 +0200 @@ -5361,13 +5361,16 @@ } j++; password = c->argv[j]->ptr; + redactClientCommandArgument(c,j); } else if (!strcasecmp(c->argv[j]->ptr,"auth2")) { if (moreargs < 2) { addReplyErrorObject(c,shared.syntaxerr); return; } username = c->argv[++j]->ptr; + redactClientCommandArgument(c,j); password = c->argv[++j]->ptr; + redactClientCommandArgument(c,j); } else if (!strcasecmp(c->argv[j]->ptr,"keys")) { if (sdslen(c->argv[3]->ptr) != 0) { addReplyError(c, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/config.c new/redis-6.2.4/src/config.c --- old/redis-6.2.3/src/config.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/config.c 2021-06-01 16:03:36.000000000 +0200 @@ -726,7 +726,7 @@ (config->alias && !strcasecmp(c->argv[2]->ptr,config->alias)))) { if (config->flags & SENSITIVE_CONFIG) { - preventCommandLogging(c); + redactClientCommandArgument(c,3); } if (!config->interface.set(config->data,o->ptr,1,&errstr)) { goto badfmt; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/lazyfree.c new/redis-6.2.4/src/lazyfree.c --- old/redis-6.2.3/src/lazyfree.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/lazyfree.c 2021-06-01 16:03:36.000000000 +0200 @@ -109,7 +109,7 @@ /* Every consumer group is an allocation and so are the entries in its * PEL. We use size of the first group's PEL as an estimate for all * others. */ - if (s->cgroups) { + if (s->cgroups && raxSize(s->cgroups)) { raxIterator ri; streamCG *cg; raxStart(&ri,s->cgroups); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/multi.c new/redis-6.2.4/src/multi.c --- old/redis-6.2.3/src/multi.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/multi.c 2021-06-01 16:03:36.000000000 +0200 @@ -153,8 +153,7 @@ /* Send EXEC to clients waiting data from MONITOR. We did send a MULTI * already, and didn't send any of the queued commands, now we'll just send * EXEC so it is clear that the transaction is over. */ - if (listLength(server.monitors) && !server.loading) - replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); + replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); } void execCommand(client *c) { @@ -179,7 +178,7 @@ addReply(c, c->flags & CLIENT_DIRTY_EXEC ? shared.execaborterr : shared.nullarray[c->resp]); discardTransaction(c); - goto handle_monitor; + return; } uint64_t old_flags = c->flags; @@ -266,15 +265,6 @@ } server.in_exec = 0; - -handle_monitor: - /* Send EXEC to clients waiting data from MONITOR. We do it here - * since the natural order of commands execution is actually: - * MUTLI, EXEC, ... commands inside transaction ... - * Instead EXEC is flagged as CMD_SKIP_MONITOR in the command - * table, and we do it here with correct ordering. */ - if (listLength(server.monitors) && !server.loading) - replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); } /* ===================== WATCH (CAS alike for MULTI/EXEC) =================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/networking.c new/redis-6.2.4/src/networking.c --- old/redis-6.2.3/src/networking.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/networking.c 2021-06-01 16:03:36.000000000 +0200 @@ -333,7 +333,7 @@ listAddNodeTail(c->reply, tail); c->reply_bytes += tail->size; - asyncCloseClientOnOutputBufferLimitReached(c); + closeClientOnOutputBufferLimitReached(c, 1); } } @@ -616,7 +616,7 @@ listNodeValue(ln) = buf; c->reply_bytes += buf->size; - asyncCloseClientOnOutputBufferLimitReached(c); + closeClientOnOutputBufferLimitReached(c, 1); } } @@ -949,7 +949,7 @@ src->bufpos = 0; /* Check output buffer limits */ - asyncCloseClientOnOutputBufferLimitReached(dst); + closeClientOnOutputBufferLimitReached(dst, 1); } /* Copy 'src' client output buffers into 'dst' client output buffers. @@ -1663,9 +1663,6 @@ c->flags |= CLIENT_REPLY_SKIP; c->flags &= ~CLIENT_REPLY_SKIP_NEXT; } - - /* Always clear the prevent logging field. */ - c->flags &= ~CLIENT_PREVENT_LOGGING; } /* This function is used when we want to re-enter the event loop but there @@ -2967,7 +2964,8 @@ int moreargs = (c->argc-1) - j; const char *opt = c->argv[j]->ptr; if (!strcasecmp(opt,"AUTH") && moreargs >= 2) { - preventCommandLogging(c); + redactClientCommandArgument(c, j+1); + redactClientCommandArgument(c, j+2); if (ACLAuthenticateUser(c, c->argv[j+1], c->argv[j+2]) == C_ERR) { addReplyError(c,"-WRONGPASS invalid username-password pair or user is disabled."); return; @@ -3054,6 +3052,15 @@ } } +/* Redact a given argument to prevent it from being shown + * in the slowlog. This information is stored in the + * original_argv array. */ +void redactClientCommandArgument(client *c, int argc) { + retainOriginalCommandVector(c); + decrRefCount(c->argv[argc]); + c->original_argv[argc] = shared.redacted; +} + /* Rewrite the command vector of the client. All the new objects ref count * is incremented. The old command vector is freed, and the old objects * ref count is decremented. */ @@ -3223,18 +3230,33 @@ * * Note: we need to close the client asynchronously because this function is * called from contexts where the client can't be freed safely, i.e. from the - * lower level functions pushing data inside the client output buffers. */ -void asyncCloseClientOnOutputBufferLimitReached(client *c) { - if (!c->conn) return; /* It is unsafe to free fake clients. */ + * lower level functions pushing data inside the client output buffers. + * When `async` is set to 0, we close the client immediately, this is + * useful when called from cron. + * + * Returns 1 if client was (flagged) closed. */ +int closeClientOnOutputBufferLimitReached(client *c, int async) { + if (!c->conn) return 0; /* It is unsafe to free fake clients. */ serverAssert(c->reply_bytes < SIZE_MAX-(1024*64)); - if (c->reply_bytes == 0 || c->flags & CLIENT_CLOSE_ASAP) return; + if (c->reply_bytes == 0 || c->flags & CLIENT_CLOSE_ASAP) return 0; if (checkClientOutputBufferLimits(c)) { sds client = catClientInfoString(sdsempty(),c); - freeClientAsync(c); - serverLog(LL_WARNING,"Client %s scheduled to be closed ASAP for overcoming of output buffer limits.", client); + if (async) { + freeClientAsync(c); + serverLog(LL_WARNING, + "Client %s scheduled to be closed ASAP for overcoming of output buffer limits.", + client); + } else { + freeClient(c); + serverLog(LL_WARNING, + "Client %s closed for overcoming of output buffer limits.", + client); + } sdsfree(client); + return 1; } + return 0; } /* Helper function used by performEvictions() in order to flush slaves diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/rdb.c new/redis-6.2.4/src/rdb.c --- old/redis-6.2.3/src/rdb.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/rdb.c 2021-06-01 16:03:36.000000000 +0200 @@ -2691,6 +2691,7 @@ } if (server.rdb_child_exit_pipe!=-1) close(server.rdb_child_exit_pipe); + aeDeleteFileEvent(server.el, server.rdb_pipe_read, AE_READABLE); close(server.rdb_pipe_read); server.rdb_child_exit_pipe = -1; server.rdb_pipe_read = -1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/redis-benchmark.c new/redis-6.2.4/src/redis-benchmark.c --- old/redis-6.2.3/src/redis-benchmark.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/redis-benchmark.c 2021-06-01 16:03:36.000000000 +0200 @@ -368,9 +368,10 @@ if (hostsocket == NULL) fprintf(stderr, "%s:%d\n", ip, port); else fprintf(stderr, "%s\n", hostsocket); int abort_test = 0; - if (!strncmp(reply->str,"NOAUTH",5) || - !strncmp(reply->str,"WRONGPASS",9) || - !strncmp(reply->str,"NOPERM",5)) + if (reply && reply->type == REDIS_REPLY_ERROR && + (!strncmp(reply->str,"NOAUTH",5) || + !strncmp(reply->str,"WRONGPASS",9) || + !strncmp(reply->str,"NOPERM",5))) abort_test = 1; freeReplyObject(reply); redisFree(c); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/replication.c new/redis-6.2.4/src/replication.c --- old/redis-6.2.3/src/replication.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/replication.c 2021-06-01 16:03:36.000000000 +0200 @@ -377,6 +377,7 @@ } void replicationFeedMonitors(client *c, list *monitors, int dictid, robj **argv, int argc) { + if (!(listLength(server.monitors) && !server.loading)) return; listNode *ln; listIter li; int j; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/scripting.c new/redis-6.2.4/src/scripting.c --- old/redis-6.2.3/src/scripting.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/scripting.c 2021-06-01 16:03:36.000000000 +0200 @@ -1690,6 +1690,9 @@ } void evalCommand(client *c) { + /* Explicitly feed monitor here so that lua commands appear after their + * script command. */ + replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); if (!(c->flags & CLIENT_LUA_DEBUG)) evalGenericCommand(c,0); else @@ -1697,6 +1700,9 @@ } void evalShaCommand(client *c) { + /* Explicitly feed monitor here so that lua commands appear after their + * script command. */ + replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); if (sdslen(c->argv[1]->ptr) != 40) { /* We know that a match is not possible if the provided SHA is * not the right length. So we return an error ASAP, this way diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/sentinel.c new/redis-6.2.4/src/sentinel.c --- old/redis-6.2.3/src/sentinel.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/sentinel.c 2021-06-01 16:03:36.000000000 +0200 @@ -3175,11 +3175,13 @@ sentinel.announce_port = numval; } else if (!strcasecmp(o->ptr, "sentinel-user")) { sdsfree(sentinel.sentinel_auth_user); - sentinel.sentinel_auth_user = sdsnew(val->ptr); + sentinel.sentinel_auth_user = sdslen(val->ptr) == 0 ? + NULL : sdsdup(val->ptr); drop_conns = 1; } else if (!strcasecmp(o->ptr, "sentinel-pass")) { sdsfree(sentinel.sentinel_auth_pass); - sentinel.sentinel_auth_pass = sdsnew(val->ptr); + sentinel.sentinel_auth_pass = sdslen(val->ptr) == 0 ? + NULL : sdsdup(val->ptr); drop_conns = 1; } else { addReplyErrorFormat(c, "Invalid argument '%s' to SENTINEL CONFIG SET", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/server.c new/redis-6.2.4/src/server.c --- old/redis-6.2.3/src/server.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/server.c 2021-06-01 16:03:36.000000000 +0200 @@ -706,7 +706,7 @@ 0,NULL,0,0,0,0,0,0}, {"auth",authCommand,-2, - "no-auth no-script ok-loading ok-stale fast no-monitor no-slowlog @connection", + "no-auth no-script ok-loading ok-stale fast @connection", 0,NULL,0,0,0,0,0,0}, /* We don't allow PING during loading since in Redis PING is used as @@ -749,7 +749,7 @@ 0,NULL,0,0,0,0,0,0}, {"exec",execCommand,1, - "no-script no-monitor no-slowlog ok-loading ok-stale @transaction", + "no-script no-slowlog ok-loading ok-stale @transaction", 0,NULL,0,0,0,0,0,0}, {"discard",discardCommand,1, @@ -901,17 +901,21 @@ 0,NULL,0,0,0,0,0,0}, {"hello",helloCommand,-1, - "no-auth no-script fast no-monitor ok-loading ok-stale @connection", + "no-auth no-script fast ok-loading ok-stale @connection", 0,NULL,0,0,0,0,0,0}, /* EVAL can modify the dataset, however it is not flagged as a write - * command since we do the check while running commands from Lua. */ + * command since we do the check while running commands from Lua. + * + * EVAL and EVALSHA also feed monitors before the commands are executed, + * as opposed to after. + */ {"eval",evalCommand,-3, - "no-script may-replicate @scripting", + "no-script no-monitor may-replicate @scripting", 0,evalGetKeys,0,0,0,0,0,0}, {"evalsha",evalShaCommand,-3, - "no-script may-replicate @scripting", + "no-script no-monitor may-replicate @scripting", 0,evalGetKeys,0,0,0,0,0,0}, {"slowlog",slowlogCommand,-2, @@ -1839,6 +1843,7 @@ if (clientsCronResizeQueryBuffer(c)) continue; if (clientsCronTrackExpansiveClients(c, curr_peak_mem_usage_slot)) continue; if (clientsCronTrackClientsMemUsage(c)) continue; + if (closeClientOnOutputBufferLimitReached(c, 0)) continue; } } @@ -2603,6 +2608,7 @@ shared.getack = createStringObject("GETACK",6); shared.special_asterick = createStringObject("*",1); shared.special_equals = createStringObject("=",1); + shared.redacted = makeObjectShared(createStringObject("(redacted)",10)); for (j = 0; j < OBJ_SHARED_INTEGERS; j++) { shared.integers[j] = @@ -3624,12 +3630,6 @@ c->flags |= CLIENT_PREVENT_PROP; } -/* Avoid logging any information about this client's arguments - * since they contain sensitive information. */ -void preventCommandLogging(client *c) { - c->flags |= CLIENT_PREVENT_LOGGING; -} - /* AOF specific version of preventCommandPropagation(). */ void preventCommandAOF(client *c) { c->flags |= CLIENT_PREVENT_AOF_PROP; @@ -3643,7 +3643,7 @@ /* Log the last command a client executed into the slowlog. */ void slowlogPushCurrentCommand(client *c, struct redisCommand *cmd, ustime_t duration) { /* Some commands may contain sensitive data that should not be available in the slowlog. */ - if ((c->flags & CLIENT_PREVENT_LOGGING) || (cmd->flags & CMD_SKIP_SLOWLOG)) + if (cmd->flags & CMD_SKIP_SLOWLOG) return; /* If command argument vector was rewritten, use the original @@ -3699,15 +3699,6 @@ server.fixed_time_expire++; - /* Send the command to clients in MONITOR mode if applicable. - * Administrative commands are considered too dangerous to be shown. */ - if (listLength(server.monitors) && - !server.loading && - !(c->cmd->flags & (CMD_SKIP_MONITOR|CMD_ADMIN))) - { - replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); - } - /* Initialization: clear the flags that must be set by the command on * demand, and initialize the array for additional commands propagation. */ c->flags &= ~(CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP); @@ -3773,6 +3764,14 @@ if ((flags & CMD_CALL_SLOWLOG) && !(c->flags & CLIENT_BLOCKED)) slowlogPushCurrentCommand(c, real_cmd, duration); + /* Send the command to clients in MONITOR mode if applicable. + * Administrative commands are considered too dangerous to be shown. */ + if (!(c->cmd->flags & (CMD_SKIP_MONITOR|CMD_ADMIN))) { + robj **argv = c->original_argv ? c->original_argv : c->argv; + int argc = c->original_argv ? c->original_argc : c->argc; + replicationFeedMonitors(c,server.monitors,c->db->id,argv,argc); + } + /* Clear the original argv. * If the client is blocked we will handle slowlog when it is unblocked. */ if (!(c->flags & CLIENT_BLOCKED)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/server.h new/redis-6.2.4/src/server.h --- old/redis-6.2.3/src/server.h 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/server.h 2021-06-01 16:03:36.000000000 +0200 @@ -279,7 +279,6 @@ and AOF client */ #define CLIENT_REPL_RDBONLY (1ULL<<42) /* This client is a replica that only wants RDB without replication buffer. */ -#define CLIENT_PREVENT_LOGGING (1ULL<<43) /* Prevent logging of command to slowlog */ /* Client block type (btype field in client structure) * if CLIENT_BLOCKED flag is set. */ @@ -986,7 +985,7 @@ *script, *replconf, *eval, *persist, *set, *pexpireat, *pexpire, *time, *pxat, *px, *retrycount, *force, *justid, *lastid, *ping, *setid, *keepttl, *load, *createconsumer, - *getack, *special_asterick, *special_equals, *default_username, + *getack, *special_asterick, *special_equals, *default_username, *redacted, *select[PROTO_SHARED_SELECT_CMDS], *integers[OBJ_SHARED_INTEGERS], *mbulkhdr[OBJ_SHARED_BULKHDR_LEN], /* "*<value>\r\n" */ @@ -1865,9 +1864,10 @@ void rewriteClientCommandVector(client *c, int argc, ...); void rewriteClientCommandArgument(client *c, int i, robj *newval); void replaceClientCommandVector(client *c, int argc, robj **argv); +void redactClientCommandArgument(client *c, int argc); unsigned long getClientOutputBufferMemoryUsage(client *c); int freeClientsInAsyncFreeQueue(void); -void asyncCloseClientOnOutputBufferLimitReached(client *c); +int closeClientOnOutputBufferLimitReached(client *c, int async); int getClientType(client *c); int getClientTypeByName(char *name); char *getClientTypeName(int class); @@ -2213,7 +2213,6 @@ void redisOpArrayFree(redisOpArray *oa); void forceCommandPropagation(client *c, int flags); void preventCommandPropagation(client *c); -void preventCommandLogging(client *c); void preventCommandAOF(client *c); void preventCommandReplication(client *c); void slowlogPushCurrentCommand(client *c, struct redisCommand *cmd, ustime_t duration); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/t_set.c new/redis-6.2.4/src/t_set.c --- old/redis-6.2.3/src/t_set.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/t_set.c 2021-06-01 16:03:36.000000000 +0200 @@ -869,6 +869,7 @@ if (dstkey) { if (dbDelete(c->db,dstkey)) { signalModifiedKey(c,c->db,dstkey); + notifyKeyspaceEvent(NOTIFY_GENERIC,"del",dstkey,c->db->id); server.dirty++; } addReply(c,shared.czero); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/t_string.c new/redis-6.2.4/src/t_string.c --- old/redis-6.2.3/src/t_string.c 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/t_string.c 2021-06-01 16:03:36.000000000 +0200 @@ -797,6 +797,12 @@ goto cleanup; } + /* Detect string truncation or later overflows. */ + if (sdslen(a) >= UINT32_MAX-1 || sdslen(b) >= UINT32_MAX-1) { + addReplyError(c, "String too long for LCS"); + goto cleanup; + } + /* Compute the LCS using the vanilla dynamic programming technique of * building a table of LCS(x,y) substrings. */ uint32_t alen = sdslen(a); @@ -805,9 +811,19 @@ /* Setup an uint32_t array to store at LCS[i,j] the length of the * LCS A0..i-1, B0..j-1. Note that we have a linear array here, so * we index it as LCS[j+(blen+1)*j] */ - uint32_t *lcs = zmalloc((size_t)(alen+1)*(blen+1)*sizeof(uint32_t)); #define LCS(A,B) lcs[(B)+((A)*(blen+1))] + /* Try to allocate the LCS table, and abort on overflow or insufficient memory. */ + unsigned long long lcssize = (unsigned long long)(alen+1)*(blen+1); /* Can't overflow due to the size limits above. */ + unsigned long long lcsalloc = lcssize * sizeof(uint32_t); + uint32_t *lcs = NULL; + if (lcsalloc < SIZE_MAX && lcsalloc / lcssize == sizeof(uint32_t)) + lcs = ztrymalloc(lcsalloc); + if (!lcs) { + addReplyError(c, "Insufficient memory"); + goto cleanup; + } + /* Start building the LCS table. */ for (uint32_t i = 0; i <= alen; i++) { for (uint32_t j = 0; j <= blen; j++) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/src/version.h new/redis-6.2.4/src/version.h --- old/redis-6.2.3/src/version.h 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/src/version.h 2021-06-01 16:03:36.000000000 +0200 @@ -1,2 +1,2 @@ -#define REDIS_VERSION "6.2.3" -#define REDIS_VERSION_NUM 0x00060203 +#define REDIS_VERSION "6.2.4" +#define REDIS_VERSION_NUM 0x00060204 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/tests/integration/replication.tcl new/redis-6.2.4/tests/integration/replication.tcl --- old/redis-6.2.3/tests/integration/replication.tcl 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/tests/integration/replication.tcl 2021-06-01 16:03:36.000000000 +0200 @@ -774,6 +774,45 @@ } } +test "diskless replication read pipe cleanup" { + # In diskless replication, we create a read pipe for the RDB, between the child and the parent. + # When we close this pipe (fd), the read handler also needs to be removed from the event loop (if it still registered). + # Otherwise, next time we will use the same fd, the registration will be fail (panic), because + # we will use EPOLL_CTL_MOD (the fd still register in the event loop), on fd that already removed from epoll_ctl + start_server {tags {"repl"}} { + set master [srv 0 client] + set master_host [srv 0 host] + set master_port [srv 0 port] + set master_pid [srv 0 pid] + $master config set repl-diskless-sync yes + $master config set repl-diskless-sync-delay 0 + + # put enough data in the db, and slowdown the save, to keep the parent busy at the read process + $master config set rdb-key-save-delay 100000 + $master debug populate 20000 test 10000 + $master config set rdbcompression no + start_server {} { + set replica [srv 0 client] + set loglines [count_log_lines 0] + $replica config set repl-diskless-load swapdb + $replica replicaof $master_host $master_port + + # wait for the replicas to start reading the rdb + wait_for_log_messages 0 {"*Loading DB in memory*"} $loglines 800 10 + + set loglines [count_log_lines 0] + # send FLUSHALL so the RDB child will be killed + $master flushall + + # wait for another RDB child process to be started + wait_for_log_messages -1 {"*Background RDB transfer started by pid*"} $loglines 800 10 + + # make sure master is alive + $master ping + } + } +} + test {replicaof right after disconnection} { # this is a rare race condition that was reproduced sporadically by the psync2 unit. # see details in #7205 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/tests/unit/introspection.tcl new/redis-6.2.4/tests/unit/introspection.tcl --- old/redis-6.2.3/tests/unit/introspection.tcl 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/tests/unit/introspection.tcl 2021-06-01 16:03:36.000000000 +0200 @@ -31,6 +31,52 @@ assert_match {*lua*"set"*"foo"*"bar"*} [$rd read] } + test {MONITOR supports redacting command arguments} { + set rd [redis_deferring_client] + $rd monitor + $rd read ; # Discard the OK + + r migrate [srv 0 host] [srv 0 port] key 9 5000 + r migrate [srv 0 host] [srv 0 port] key 9 5000 AUTH user + r migrate [srv 0 host] [srv 0 port] key 9 5000 AUTH2 user password + catch {r auth not-real} _ + catch {r auth not-real not-a-password} _ + catch {r hello 2 AUTH not-real not-a-password} _ + + assert_match {*"key"*"9"*"5000"*} [$rd read] + assert_match {*"key"*"9"*"5000"*"(redacted)"*} [$rd read] + assert_match {*"key"*"9"*"5000"*"(redacted)"*"(redacted)"*} [$rd read] + assert_match {*"auth"*"(redacted)"*} [$rd read] + assert_match {*"auth"*"(redacted)"*"(redacted)"*} [$rd read] + assert_match {*"hello"*"2"*"AUTH"*"(redacted)"*"(redacted)"*} [$rd read] + $rd close + } + + test {MONITOR correctly handles multi-exec cases} { + set rd [redis_deferring_client] + $rd monitor + $rd read ; # Discard the OK + + # Make sure multi-exec statements are ordered + # correctly + r multi + r set foo bar + r exec + assert_match {*"multi"*} [$rd read] + assert_match {*"set"*"foo"*"bar"*} [$rd read] + assert_match {*"exec"*} [$rd read] + + # Make sure we close multi statements on errors + r multi + catch {r syntax error} _ + catch {r exec} _ + + assert_match {*"multi"*} [$rd read] + assert_match {*"exec"*} [$rd read] + + $rd close + } + test {CLIENT GETNAME should return NIL if name is not assigned} { r client getname } {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/tests/unit/obuf-limits.tcl new/redis-6.2.4/tests/unit/obuf-limits.tcl --- old/redis-6.2.3/tests/unit/obuf-limits.tcl 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/tests/unit/obuf-limits.tcl 2021-06-01 16:03:36.000000000 +0200 @@ -18,65 +18,72 @@ assert {$omem >= 70000 && $omem < 200000} $rd1 close } - - test {Client output buffer soft limit is not enforced if time is not overreached} { - r config set client-output-buffer-limit {pubsub 0 100000 10} - set rd1 [redis_deferring_client] - - $rd1 subscribe foo - set reply [$rd1 read] - assert {$reply eq "subscribe foo 1"} - - set omem 0 - set start_time 0 - set time_elapsed 0 - while 1 { - if {$start_time != 0} { - # Slow down loop when omen has reached the limit. - after 10 - } - r publish foo [string repeat "x" 1000] - set clients [split [r client list] "\r\n"] - set c [split [lindex $clients 1] " "] - if {![regexp {omem=([0-9]+)} $c - omem]} break - if {$omem > 100000} { - if {$start_time == 0} {set start_time [clock seconds]} - set time_elapsed [expr {[clock seconds]-$start_time}] - if {$time_elapsed >= 5} break - } + + foreach {soft_limit_time wait_for_timeout} {3 yes + 4 no } { + if $wait_for_timeout { + set test_name "Client output buffer soft limit is enforced if time is overreached" + } else { + set test_name "Client output buffer soft limit is not enforced too early and is enforced when no traffic" } - assert {$omem >= 100000 && $time_elapsed >= 5 && $time_elapsed <= 10} - $rd1 close - } - test {Client output buffer soft limit is enforced if time is overreached} { - r config set client-output-buffer-limit {pubsub 0 100000 3} - set rd1 [redis_deferring_client] - - $rd1 subscribe foo - set reply [$rd1 read] - assert {$reply eq "subscribe foo 1"} - - set omem 0 - set start_time 0 - set time_elapsed 0 - while 1 { - if {$start_time != 0} { - # Slow down loop when omen has reached the limit. - after 10 + test $test_name { + r config set client-output-buffer-limit "pubsub 0 100000 $soft_limit_time" + set soft_limit_time [expr $soft_limit_time*1000] + set rd1 [redis_deferring_client] + + $rd1 client setname test_client + set reply [$rd1 read] + assert {$reply eq "OK"} + + $rd1 subscribe foo + set reply [$rd1 read] + assert {$reply eq "subscribe foo 1"} + + set omem 0 + set start_time 0 + set time_elapsed 0 + set last_under_limit_time [clock milliseconds] + while 1 { + r publish foo [string repeat "x" 1000] + set clients [split [r client list] "\r\n"] + set c [lsearch -inline $clients *name=test_client*] + if {$start_time != 0} { + set time_elapsed [expr {[clock milliseconds]-$start_time}] + # Make sure test isn't taking too long + assert {$time_elapsed <= [expr $soft_limit_time+3000]} + } + if {$wait_for_timeout && $c == ""} { + # Make sure we're disconnected when we reach the soft limit + assert {$omem >= 100000 && $time_elapsed >= $soft_limit_time} + break + } else { + assert {[regexp {omem=([0-9]+)} $c - omem]} + } + if {$omem > 100000} { + if {$start_time == 0} {set start_time $last_under_limit_time} + if {!$wait_for_timeout && $time_elapsed >= [expr $soft_limit_time-1000]} break + # Slow down loop when omem has reached the limit. + after 10 + } else { + # if the OS socket buffers swallowed what we previously filled, reset the start timer. + set start_time 0 + set last_under_limit_time [clock milliseconds] + } } - r publish foo [string repeat "x" 1000] - set clients [split [r client list] "\r\n"] - set c [split [lindex $clients 1] " "] - if {![regexp {omem=([0-9]+)} $c - omem]} break - if {$omem > 100000} { - if {$start_time == 0} {set start_time [clock seconds]} - set time_elapsed [expr {[clock seconds]-$start_time}] - if {$time_elapsed >= 10} break + + if {!$wait_for_timeout} { + # After we completely stopped the traffic, wait for soft limit to time out + set timeout [expr {$soft_limit_time+1500 - ([clock milliseconds]-$start_time)}] + wait_for_condition [expr $timeout/10] 10 { + [lsearch [split [r client list] "\r\n"] *name=test_client*] == -1 + } else { + fail "Soft limit timed out but client still connected" + } } + + $rd1 close } - assert {$omem >= 100000 && $time_elapsed < 6} - $rd1 close } test {No response for single command if client output buffer hard limit is enforced} { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/tests/unit/other.tcl new/redis-6.2.4/tests/unit/other.tcl --- old/redis-6.2.3/tests/unit/other.tcl 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/tests/unit/other.tcl 2021-06-01 16:03:36.000000000 +0200 @@ -266,9 +266,6 @@ assert_equal [$rd read] "OK" $rd reset - - # skip reset ouptut - $rd read assert_equal [$rd read] "RESET" assert_no_match {*flags=O*} [r client list] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-6.2.3/tests/unit/slowlog.tcl new/redis-6.2.4/tests/unit/slowlog.tcl --- old/redis-6.2.3/tests/unit/slowlog.tcl 2021-05-03 21:57:00.000000000 +0200 +++ new/redis-6.2.4/tests/unit/slowlog.tcl 2021-06-01 16:03:36.000000000 +0200 @@ -45,18 +45,35 @@ r config set slowlog-log-slower-than 0 r slowlog reset r config set masterauth "" - r acl setuser slowlog-test-user + r acl setuser slowlog-test-user +get +set r config set slowlog-log-slower-than 0 r config set slowlog-log-slower-than 10000 set slowlog_resp [r slowlog get] # Make sure normal configs work, but the two sensitive - # commands are omitted - assert_equal 2 [llength $slowlog_resp] - assert_equal {slowlog reset} [lindex [lindex [r slowlog get] 1] 3] + # commands are omitted or redacted + assert_equal 4 [llength $slowlog_resp] + assert_equal {slowlog reset} [lindex [lindex [r slowlog get] 3] 3] + assert_equal {config set masterauth (redacted)} [lindex [lindex [r slowlog get] 2] 3] + assert_equal {acl setuser (redacted) (redacted) (redacted)} [lindex [lindex [r slowlog get] 1] 3] assert_equal {config set slowlog-log-slower-than 0} [lindex [lindex [r slowlog get] 0] 3] } + test {SLOWLOG - Some commands can redact sensitive fields} { + r config set slowlog-log-slower-than 0 + r slowlog reset + r migrate [srv 0 host] [srv 0 port] key 9 5000 + r migrate [srv 0 host] [srv 0 port] key 9 5000 AUTH user + r migrate [srv 0 host] [srv 0 port] key 9 5000 AUTH2 user password + + r config set slowlog-log-slower-than 10000 + # Make sure all 3 commands were logged, but the sensitive fields are omitted + assert_equal 4 [llength [r slowlog get]] + assert_match {* key 9 5000} [lindex [lindex [r slowlog get] 2] 3] + assert_match {* key 9 5000 AUTH (redacted)} [lindex [lindex [r slowlog get] 1] 3] + assert_match {* key 9 5000 AUTH2 (redacted) (redacted)} [lindex [lindex [r slowlog get] 0] 3] + } + test {SLOWLOG - Rewritten commands are logged as their original command} { r config set slowlog-log-slower-than 0 ++++++ redis.hashes ++++++ --- /var/tmp/diff_new_pack.GQ2NvC/_old 2021-06-04 22:42:39.279069106 +0200 +++ /var/tmp/diff_new_pack.GQ2NvC/_new 2021-06-04 22:42:39.279069106 +0200 @@ -125,3 +125,5 @@ hash redis-6.2.2.tar.gz sha256 7a260bb74860f1b88c3d5942bf8ba60ca59f121c6dce42d3017bed6add0b9535 http://download.redis.io/releases/redis-6.2.2.tar.gz hash redis-6.0.13.tar.gz sha256 3049763f4553ddd5a69552f41da3dd7dde9fbc524dbb15e517fee24cc73b790c http://download.redis.io/releases/redis-6.0.13.tar.gz hash redis-6.2.3.tar.gz sha256 98ed7d532b5e9671f5df0825bb71f0f37483a16546364049384c63db8764512b http://download.redis.io/releases/redis-6.2.3.tar.gz +hash redis-6.0.14.tar.gz sha256 c3e60c928b183ca9fe8e878936a6f8ba99e0441b9b6e04d2412a750ea576c649 http://download.redis.io/releases/redis-6.0.14.tar.gz +hash redis-6.2.4.tar.gz sha256 ba32c406a10fc2c09426e2be2787d74ff204eb3a2e496d87cff76a476b6ae16e http://download.redis.io/releases/redis-6.2.4.tar.gz