From 9317bf64659b33166a943ec03d5d9b954e86afb0 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)

CVE: CVE-2024-31228

Upstream-Status: Backport[https://github.com/redis/redis/commit/9317bf64659b33166a943ec03d5d9b954e86afb0]

Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
---
 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 8ce2c5f..3a4c9b0 100644
--- a/src/util.c
+++ b/src/util.c
@@ -51,8 +51,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 '*':
@@ -64,7 +67,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 */
@@ -186,7 +189,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 437f71f..988389f 100644
--- a/tests/unit/keyspace.tcl
+++ b/tests/unit/keyspace.tcl
@@ -495,4 +495,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.40.0

