diff --git a/00-RELEASENOTES b/00-RELEASENOTES index 1f73d93218..30e6cdbc2f 100644 --- a/00-RELEASENOTES +++ b/00-RELEASENOTES @@ -25,6 +25,13 @@ Bug fixes * Resolved issues in replicationSetPrimary where the primary node's IP/port updates were not correctly handled in the cluster gossip section. (#965) +Security fixes +============== + +* (CVE-2024-31449) Lua library commands may lead to stack overflow and potential RCE. +* (CVE-2024-31227) Potential Denial-of-service due to malformed ACL selectors. +* (CVE-2024-31228) Potential Denial-of-service due to unbounded pattern matching. + ================================================================================ Valkey 7.2.6 GA - Released Tue 30 July 2024 ================================================================================ diff --git a/deps/lua/src/lua_bit.c b/deps/lua/src/lua_bit.c index 9f83b8594b..7e43faea47 100644 --- a/deps/lua/src/lua_bit.c +++ b/deps/lua/src/lua_bit.c @@ -132,6 +132,7 @@ static int bit_tohex(lua_State *L) const char *hexdigits = "0123456789abcdef"; char buf[8]; int i; + if (n == INT32_MIN) n = INT32_MIN+1; if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; } if (n > 8) n = 8; for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; } diff --git a/src/acl.c b/src/acl.c index 683e5434d0..07cb612ab6 100644 --- a/src/acl.c +++ b/src/acl.c @@ -1051,7 +1051,7 @@ int ACLSetSelector(aclSelector *selector, const char* op, size_t oplen) { flags |= ACL_READ_PERMISSION; } else if (toupper(op[offset]) == 'W' && !(flags & ACL_WRITE_PERMISSION)) { flags |= ACL_WRITE_PERMISSION; - } else if (op[offset] == '~') { + } else if (op[offset] == '~' && flags) { offset++; break; } else { diff --git a/src/util.c b/src/util.c index 62d789be9b..b1e89c97b1 100644 --- a/src/util.c +++ b/src/util.c @@ -54,8 +54,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 '*': @@ -67,7 +70,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 */ @@ -189,7 +192,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/acl-v2.tcl b/tests/unit/acl-v2.tcl index b259c27163..38070fb9ec 100644 --- a/tests/unit/acl-v2.tcl +++ b/tests/unit/acl-v2.tcl @@ -116,6 +116,11 @@ start_server {tags {"acl external:skip"}} { assert_match "*NOPERM*key*" $err } + test {Validate read and write permissions format} { + catch {r ACL SETUSER key-permission-RW %~} err + set err + } {ERR Error in ACL SETUSER modifier '%~': Syntax error} + test {Test separate read and write permissions on different selectors are not additive} { r ACL SETUSER key-permission-RW-selector on nopass "(%R~read* +@all)" "(%W~write* +@all)" $r2 auth key-permission-RW-selector password diff --git a/tests/unit/keyspace.tcl b/tests/unit/keyspace.tcl index 43690d06b3..b42421221c 100644 --- a/tests/unit/keyspace.tcl +++ b/tests/unit/keyspace.tcl @@ -499,4 +499,10 @@ foreach {type large} [array get largevalue] { 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] + } {} } diff --git a/tests/unit/scripting.tcl b/tests/unit/scripting.tcl index a64572b6d4..641d761224 100644 --- a/tests/unit/scripting.tcl +++ b/tests/unit/scripting.tcl @@ -641,6 +641,12 @@ start_server {tags {"scripting"}} { set e } {ERR *Attempt to modify a readonly table*} + test {lua bit.tohex bug} { + set res [run_script {return bit.tohex(65535, -2147483648)} 0] + r ping + set res + } {0000FFFF} + test {Test an example script DECR_IF_GT} { set decr_if_gt { local current