From c8649f8e852d1dc388b5446e003bb0eefa33d61f Mon Sep 17 00:00:00 2001
From: Oran Agra <oran@redislabs.com>
Date: Wed, 2 Oct 2024 20:11:01 +0300
Subject: [PATCH] Prevent pattern matching abuse (CVE-2024-31228)

---
 src/util.c              | 9 ++++++---
 tests/unit/keyspace.tcl | 6 ++++++
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/util.c b/src/util.c
index 861ef67..0f5e8e1 100644
--- a/src/util.c
+++ b/src/util.c
@@ -45,8 +45,11 @@
 
 /* Glob-style pattern matching. */
 static int stringmatchlen_impl(const char *pattern, int patternLen,
-        const char *string, int stringLen, int nocase, int *skipLongerMatches)
+        const char *string, int stringLen, int nocase, int *skipLongerMatches, int nesting)
 {
+    /* Protection against abusive patterns. */
+    if (nesting > 1000) return 0;
+
     while(patternLen && stringLen) {
         switch(pattern[0]) {
         case '*':
@@ -58,7 +61,7 @@ static int stringmatchlen_impl(const char *pattern, int patternLen,
                 return 1; /* match */
             while(stringLen) {
                if (stringmatchlen_impl(pattern+1, patternLen-1,
-                            string, stringLen, nocase, skipLongerMatches))
+                            string, stringLen, nocase, skipLongerMatches, nesting+1))
                     return 1; /* match */
                if (*skipLongerMatches)
                     return 0; /* no match */
@@ -181,7 +184,7 @@ static int stringmatchlen_impl(const char *pattern, int patternLen,
 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);
+    return stringmatchlen_impl(pattern,patternLen,string,stringLen,nocase,&skipLongerMatches,0);
 }
 
 int stringmatch(const char *pattern, const char *string, int nocase) {
diff --git a/tests/unit/keyspace.tcl b/tests/unit/keyspace.tcl
index 1617ac5..2217b29 100644
--- a/tests/unit/keyspace.tcl
+++ b/tests/unit/keyspace.tcl
@@ -278,4 +278,10 @@ start_server {tags {"keyspace"}} {
         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"
     } {}
+
+    test {Regression for pattern matching very long nested loops} {
+        r flushdb
+        r SET [string repeat "a" 50000] 1
+        r KEYS [string repeat "*?" 50000]
+    } {}
 }
-- 
2.33.0

