From 536e279934eecb6fb03f9700727981e793502372b69c520bd395b57d2b25241c Mon Sep 17 00:00:00 2001 From: Martin Pluskal Date: Thu, 2 Mar 2023 13:49:31 +0000 Subject: [PATCH] Accepting request 1068515 from home:vlefebvre:branches:server:database Fix CVE-2022-36021 (bsc#1208790) & Fix CVE-2023-25155 (bsc#1208793) OBS-URL: https://build.opensuse.org/request/show/1068515 OBS-URL: https://build.opensuse.org/package/show/server:database/redis?expand=0&rev=218 --- ...-in-RAND-commands-can-lead-to-assert.patch | 115 ++++++++++++++++++ ...atching-had-exponential-time-complex.patch | 88 ++++++++++++++ redis.changes | 8 ++ redis.spec | 6 + 4 files changed, 217 insertions(+) create mode 100644 Integer-Overflow-in-RAND-commands-can-lead-to-assert.patch create mode 100644 String-pattern-matching-had-exponential-time-complex.patch diff --git a/Integer-Overflow-in-RAND-commands-can-lead-to-assert.patch b/Integer-Overflow-in-RAND-commands-can-lead-to-assert.patch new file mode 100644 index 0000000..cd575c9 --- /dev/null +++ b/Integer-Overflow-in-RAND-commands-can-lead-to-assert.patch @@ -0,0 +1,115 @@ +From 2a2a582e7cd99ba3b531336b8bd41df2b566e619 Mon Sep 17 00:00:00 2001 +From: Oran Agra +Date: Tue, 21 Feb 2023 15:16:13 +0200 +Subject: [PATCH] Integer Overflow in RAND commands can lead to assertion + (CVE-2023-25155) + +Issue happens when passing a negative long value that greater than +the max positive value that the long can store. +--- + src/t_hash.c | 4 ++-- + src/t_set.c | 2 +- + src/t_zset.c | 4 ++-- + tests/unit/type/hash.tcl | 2 ++ + tests/unit/type/set.tcl | 5 +++++ + tests/unit/type/zset.tcl | 2 ++ + 6 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/src/t_hash.c b/src/t_hash.c +index 754315080..f4ddccc62 100644 +--- a/src/t_hash.c ++++ b/src/t_hash.c +@@ -1120,13 +1120,13 @@ void hrandfieldCommand(client *c) { + listpackEntry ele; + + if (c->argc >= 3) { +- if (getLongFromObjectOrReply(c,c->argv[2],&l,NULL) != C_OK) return; ++ if (getRangeLongFromObjectOrReply(c,c->argv[2],-LONG_MAX,LONG_MAX,&l,NULL) != C_OK) return; + if (c->argc > 4 || (c->argc == 4 && strcasecmp(c->argv[3]->ptr,"withvalues"))) { + addReplyErrorObject(c,shared.syntaxerr); + return; + } else if (c->argc == 4) { + withvalues = 1; +- if (l < LONG_MIN/2 || l > LONG_MAX/2) { ++ if (l < -LONG_MAX/2 || l > LONG_MAX/2) { + addReplyError(c,"value is out of range"); + return; + } +diff --git a/src/t_set.c b/src/t_set.c +index b01729f0a..dff66d052 100644 +--- a/src/t_set.c ++++ b/src/t_set.c +@@ -665,7 +665,7 @@ void srandmemberWithCountCommand(client *c) { + + dict *d; + +- if (getLongFromObjectOrReply(c,c->argv[2],&l,NULL) != C_OK) return; ++ if (getRangeLongFromObjectOrReply(c,c->argv[2],-LONG_MAX,LONG_MAX,&l,NULL) != C_OK) return; + if (l >= 0) { + count = (unsigned long) l; + } else { +diff --git a/src/t_zset.c b/src/t_zset.c +index 3cd2d2438..a9b5031ea 100644 +--- a/src/t_zset.c ++++ b/src/t_zset.c +@@ -4289,13 +4289,13 @@ void zrandmemberCommand(client *c) { + listpackEntry ele; + + if (c->argc >= 3) { +- if (getLongFromObjectOrReply(c,c->argv[2],&l,NULL) != C_OK) return; ++ if (getRangeLongFromObjectOrReply(c,c->argv[2],-LONG_MAX,LONG_MAX,&l,NULL) != C_OK) return; + if (c->argc > 4 || (c->argc == 4 && strcasecmp(c->argv[3]->ptr,"withscores"))) { + addReplyErrorObject(c,shared.syntaxerr); + return; + } else if (c->argc == 4) { + withscores = 1; +- if (l < LONG_MIN/2 || l > LONG_MAX/2) { ++ if (l < -LONG_MAX/2 || l > LONG_MAX/2) { + addReplyError(c,"value is out of range"); + return; + } +diff --git a/tests/unit/type/hash.tcl b/tests/unit/type/hash.tcl +index fcb42e81e..4edb146ed 100644 +--- a/tests/unit/type/hash.tcl ++++ b/tests/unit/type/hash.tcl +@@ -74,6 +74,8 @@ start_server {tags {"hash"}} { + test "HRANDFIELD count overflow" { + r hmset myhash a 1 + assert_error {*value is out of range*} {r hrandfield myhash -9223372036854770000 withvalues} ++ assert_error {*value is out of range*} {r hrandfield myhash -9223372036854775808 withvalues} ++ assert_error {*value is out of range*} {r hrandfield myhash -9223372036854775808} + } {} + + test "HRANDFIELD with against non existing key" { +diff --git a/tests/unit/type/set.tcl b/tests/unit/type/set.tcl +index 30b6dc5d7..5257dccea 100644 +--- a/tests/unit/type/set.tcl ++++ b/tests/unit/type/set.tcl +@@ -645,6 +645,11 @@ start_server { + r srandmember nonexisting_key 100 + } {} + ++ test "SRANDMEMBER count overflow" { ++ r sadd myset a ++ assert_error {*value is out of range*} {r srandmember myset -9223372036854775808} ++ } {} ++ + # Make sure we can distinguish between an empty array and a null response + r readraw 1 + +diff --git a/tests/unit/type/zset.tcl b/tests/unit/type/zset.tcl +index a758aee46..88c0bcb43 100644 +--- a/tests/unit/type/zset.tcl ++++ b/tests/unit/type/zset.tcl +@@ -2303,6 +2303,8 @@ start_server {tags {"zset"}} { + test "ZRANDMEMBER count overflow" { + r zadd myzset 0 a + assert_error {*value is out of range*} {r zrandmember myzset -9223372036854770000 withscores} ++ assert_error {*value is out of range*} {r zrandmember myzset -9223372036854775808 withscores} ++ assert_error {*value is out of range*} {r zrandmember myzset -9223372036854775808} + } {} + + # Make sure we can distinguish between an empty array and a null response +-- +2.35.3 + diff --git a/String-pattern-matching-had-exponential-time-complex.patch b/String-pattern-matching-had-exponential-time-complex.patch new file mode 100644 index 0000000..f01e710 --- /dev/null +++ b/String-pattern-matching-had-exponential-time-complex.patch @@ -0,0 +1,88 @@ +From 0825552565e5fdab2e87950579c4f0bedded3e3c Mon Sep 17 00:00:00 2001 +From: Tom Levy +Date: Tue, 21 Feb 2023 15:14:30 +0200 +Subject: [PATCH] String pattern matching had exponential time complexity on + pathological patterns (CVE-2022-36021) + +Authenticated users can use string matching commands with a +specially crafted pattern to trigger a denial-of-service attack on Redis, +causing it to hang and consume 100% CPU time. +--- + src/util.c | 27 +++++++++++++++++++++++---- + tests/unit/keyspace.tcl | 6 ++++++ + 2 files changed, 29 insertions(+), 4 deletions(-) + +diff --git a/src/util.c b/src/util.c +index e1524b5e3..8ce2c5fca 100644 +--- a/src/util.c ++++ b/src/util.c +@@ -50,8 +50,8 @@ + #include "config.h" + + /* Glob-style pattern matching. */ +-int stringmatchlen(const char *pattern, int patternLen, +- const char *string, int stringLen, int nocase) ++static int stringmatchlen_impl(const char *pattern, int patternLen, ++ const char *string, int stringLen, int nocase, int *skipLongerMatches) + { + while(patternLen && stringLen) { + switch(pattern[0]) { +@@ -63,12 +63,25 @@ int stringmatchlen(const char *pattern, int patternLen, + if (patternLen == 1) + return 1; /* match */ + while(stringLen) { +- if (stringmatchlen(pattern+1, patternLen-1, +- string, stringLen, nocase)) ++ if (stringmatchlen_impl(pattern+1, patternLen-1, ++ string, stringLen, nocase, skipLongerMatches)) + return 1; /* match */ ++ if (*skipLongerMatches) ++ return 0; /* no match */ + string++; + stringLen--; + } ++ /* There was no match for the rest of the pattern starting ++ * from anywhere in the rest of the string. If there were ++ * any '*' earlier in the pattern, we can terminate the ++ * search early without trying to match them to longer ++ * substrings. This is because a longer match for the ++ * earlier part of the pattern would require the rest of the ++ * pattern to match starting later in the string, and we ++ * have just determined that there is no match for the rest ++ * of the pattern starting from anywhere in the current ++ * string. */ ++ *skipLongerMatches = 1; + return 0; /* no match */ + break; + case '?': +@@ -170,6 +183,12 @@ int stringmatchlen(const char *pattern, int patternLen, + return 0; + } + ++int stringmatchlen(const char *pattern, int patternLen, ++ const char *string, int stringLen, int nocase) { ++ int skipLongerMatches = 0; ++ return stringmatchlen_impl(pattern,patternLen,string,stringLen,nocase,&skipLongerMatches); ++} ++ + int stringmatch(const char *pattern, const char *string, int nocase) { + return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase); + } +diff --git a/tests/unit/keyspace.tcl b/tests/unit/keyspace.tcl +index f5f971140..437f71fa1 100644 +--- a/tests/unit/keyspace.tcl ++++ b/tests/unit/keyspace.tcl +@@ -489,4 +489,10 @@ start_server {tags {"keyspace"}} { + r keys * + r keys * + } {dlskeriewrioeuwqoirueioqwrueoqwrueqw} ++ ++ test {Regression for pattern matching long nested loops} { ++ r flushdb ++ r SET aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1 ++ r KEYS "a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*b" ++ } {} + } +-- +2.35.3 + diff --git a/redis.changes b/redis.changes index 2099068..fac632f 100644 --- a/redis.changes +++ b/redis.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Wed Mar 1 16:29:28 UTC 2023 - Valentin Lefebvre + +- Fix CVE-2022-36021 (bsc#1208790 CVE-2022-36021) + * String-pattern-matching-had-exponential-time-complex.patch +- Fix CVE-2023-25155 (bsc#1208793 CVE-2023-25155) + * Integer-Overflow-in-RAND-commands-can-lead-to-assert.patch + ------------------------------------------------------------------- Mon Jan 16 21:00:00 UTC 2023 - Andreas Stieger diff --git a/redis.spec b/redis.spec index 8dc3f9a..51f0493 100644 --- a/redis.spec +++ b/redis.spec @@ -40,6 +40,10 @@ Source10: https://raw.githubusercontent.com/redis/redis-hashes/master/READ Patch0: %{name}-conf.patch Patch3: reproducible.patch Patch4: ppc-atomic.patch +# PATCH-FIX-UPSTREAM -- based on commit 0825552 (bsc#1208790 CVE-2022-36021) +Patch5: String-pattern-matching-had-exponential-time-complex.patch +# PATCH-FIX-UPSTREAM -- based on commit 2a2a582 (bsc#1208793 CVE-2023-25155) +Patch6: Integer-Overflow-in-RAND-commands-can-lead-to-assert.patch BuildRequires: jemalloc-devel BuildRequires: libopenssl-devel >= 1.1.1 BuildRequires: pkgconfig @@ -67,6 +71,8 @@ echo "`grep -F %{name}-%{version}.tar.gz %{SOURCE10} | cut -d' ' -f4` %{SOURCE0 %patch0 %patch3 -p1 %patch4 -p1 +%patch5 -p1 +%patch6 -p1 %build export HOST=OBS # for reproducible builds