Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package valkey for openSUSE:Factory checked 
in at 2026-10-01 16:59:44
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/valkey (Old)
 and      /work/SRC/openSUSE:Factory/.valkey.new.1253 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "valkey"

Thu Oct  1 16:59:44 2026 rev:25 rq:1381537 version:9.1.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/valkey/valkey.changes    2026-09-17 
15:23:29.146210616 +0200
+++ /work/SRC/openSUSE:Factory/.valkey.new.1253/valkey.changes  2026-10-01 
16:59:46.214993435 +0200
@@ -1,0 +2,8 @@
+Tue Sep 29 18:52:37 UTC 2026 - Antonio Teixeira <[email protected]>
+
+- Fix CVE-2026-92925, failure to properly validate string-carrying extensions
+  for null-termination in the cluster bus packet parser can lead to an
+  out-of-bounds read (bsc#1281417)
+  * CVE-2026-92925.patch
+
+-------------------------------------------------------------------

New:
----
  CVE-2026-92925.patch

----------(New B)----------
  New:  out-of-bounds read (bsc#1281417)
  * CVE-2026-92925.patch
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ valkey.spec ++++++
--- /var/tmp/diff_new_pack.5xtvOk/_old  2026-10-01 16:59:47.049028372 +0200
+++ /var/tmp/diff_new_pack.5xtvOk/_new  2026-10-01 16:59:47.050028413 +0200
@@ -43,6 +43,12 @@
 Source9:        %{name}-user.conf
 Source10:       macros.%{name}
 Source11:       migrate_redis_to_valkey.bash
+# PATCH-FIX-OPENSUSE bsc#1281417 CVE-2026-92925
+# failure to properly validate string-carrying extensions for null-termination 
in the cluster bus packet parser can lead to an out-of-bounds read
+# Based on upstream PRs still under review:
+# https://github.com/valkey-io/valkey/pull/4661
+# https://github.com/valkey-io/valkey/pull/4662
+Patch0:         CVE-2026-92925.patch
 # PATCH-FIX-OPENSUSE -- Adjust configs for openSUSE
 Patch1001:      %{name}-conf.patch
 BuildRequires:  jemalloc-devel

++++++ CVE-2026-92925.patch ++++++
diff --git a/src/cluster_legacy.c b/src/cluster_legacy.c
index 3bdc40e9d..83a807b8e 100644
--- a/src/cluster_legacy.c
+++ b/src/cluster_legacy.c
@@ -3369,6 +3369,24 @@ static uint32_t getForgottenNodeExtSize(void) {
     return getAlignedPingExtSize(sizeof(clusterMsgPingExtForgottenNode));
 }
 
+/* Return the minimum encoded size for an extension type. Unknown extensions
+ * only require the common header to preserve forward compatibility. */
+static uint32_t getMinimumPingExtSize(uint16_t type) {
+    switch (type) {
+    case CLUSTERMSG_EXT_TYPE_HOSTNAME: return 
getAlignedPingExtSize(sizeof(clusterMsgPingExtHostname));
+    case CLUSTERMSG_EXT_TYPE_HUMAN_NODENAME: return 
getAlignedPingExtSize(sizeof(clusterMsgPingExtHumanNodename));
+    case CLUSTERMSG_EXT_TYPE_FORGOTTEN_NODE: return getForgottenNodeExtSize();
+    case CLUSTERMSG_EXT_TYPE_SHARDID: return getShardIdPingExtSize();
+    case CLUSTERMSG_EXT_TYPE_CLIENT_IPV4: return 
getAlignedPingExtSize(sizeof(clusterMsgPingExtClientIpV4));
+    case CLUSTERMSG_EXT_TYPE_CLIENT_IPV6: return 
getAlignedPingExtSize(sizeof(clusterMsgPingExtClientIpV6));
+    case CLUSTERMSG_EXT_TYPE_CLIENT_PORT: return 
getAlignedPingExtSize(sizeof(clusterMsgPingExtClientPort));
+    case CLUSTERMSG_EXT_TYPE_CLIENT_TLS_PORT: return 
getAlignedPingExtSize(sizeof(clusterMsgPingExtClientTlsPort));
+    case CLUSTERMSG_EXT_TYPE_AVAILABILITY_ZONE:
+        return 
getAlignedPingExtSize(sizeof(clusterMsgPingExtAvailabilityZone));
+    default: return sizeof(clusterMsgPingExt);
+    }
+}
+
 static void *preparePingExt(clusterMsgPingExt *ext, uint16_t type, uint32_t 
length) {
     ext->type = htons(type);
     ext->length = htonl(length);
@@ -3720,6 +3738,13 @@ int clusterIsValidPacket(clusterLink *link) {
             return 0;
         }
 
+        if (!(msg->mflags[0] & CLUSTERMSG_FLAG0_EXT_DATA) && extensions != 0) {
+            serverLog(LL_WARNING,
+                      "Received invalid %s packet with %d extensions but no 
extension data flag",
+                      clusterGetMessageTypeString(type), extensions);
+            return 0;
+        }
+
         /* If there is extension data, which doesn't have a fixed length,
          * loop through them and validate the length of it now. */
         if (msg->mflags[0] & CLUSTERMSG_FLAG0_EXT_DATA) {
@@ -3740,6 +3765,14 @@ int clusterIsValidPacket(clusterLink *link) {
                               clusterGetMessageTypeString(type), (int)extlen);
                     return 0;
                 }
+                uint16_t ext_type = ntohs(ext->type);
+                uint32_t min_extlen = getMinimumPingExtSize(ext_type);
+                if (extlen < min_extlen) {
+                    serverLog(LL_WARNING,
+                              "Received invalid %s packet with extension type 
%d that is %d bytes but requires at least %d",
+                              clusterGetMessageTypeString(type), 
(int)ext_type, (int)extlen, (int)min_extlen);
+                    return 0;
+                }
                 /* Similar check to earlier, but we want to make sure the 
extension length is valid
                  * this time. */
                 if ((totlen - explen) < extlen) {
@@ -3749,6 +3782,20 @@ int clusterIsValidPacket(clusterLink *link) {
                               clusterGetMessageTypeString(type), (unsigned 
long long)totlen);
                     return 0;
                 }
+                bool is_string_ext = ext_type == CLUSTERMSG_EXT_TYPE_HOSTNAME 
||
+                                     ext_type == 
CLUSTERMSG_EXT_TYPE_HUMAN_NODENAME ||
+                                     ext_type == 
CLUSTERMSG_EXT_TYPE_CLIENT_IPV4 ||
+                                     ext_type == 
CLUSTERMSG_EXT_TYPE_CLIENT_IPV6 ||
+                                     ext_type == 
CLUSTERMSG_EXT_TYPE_AVAILABILITY_ZONE;
+                /* String extensions are consumed as C strings. Make sure 
those reads
+                 * cannot continue past the declared extension. */
+                if (is_string_ext &&
+                    (extlen <= sizeof(clusterMsgPingExt) ||
+                     memchr((char *)ext + sizeof(clusterMsgPingExt), '\0', 
extlen - sizeof(clusterMsgPingExt)) == NULL)) {
+                    serverLog(LL_WARNING, "Received invalid %s packet with 
unterminated string extension type %d",
+                              clusterGetMessageTypeString(type), 
(int)ext_type);
+                    return 0;
+                }
                 explen += extlen;
                 ext = getNextPingExt(ext);
             }
diff --git a/tests/unit/cluster/packet.tcl b/tests/unit/cluster/packet.tcl
index ab3313eb5..4618bd30a 100644
--- a/tests/unit/cluster/packet.tcl
+++ b/tests/unit/cluster/packet.tcl
@@ -213,6 +213,113 @@ start_cluster 1 0 {tags {external:skip cluster tls:skip}} 
{
     }
 }
 
+start_cluster 1 0 {tags {external:skip cluster tls:skip}} {
+    test "Reject extension count without extension data flag" {
+        set base_port [srv 0 port]
+        set cluster_port [expr {$base_port + 10000}]
+        set sender_node_id [R 0 cluster myid]
+
+        set packet [create_cluster_meet_packet \
+            $sender_node_id $base_port $cluster_port 0 1 0]
+
+        set loglines [count_log_lines 0]
+        set sock [socket 127.0.0.1 $cluster_port]
+        fconfigure $sock -translation binary -buffering none -blocking 1
+        puts -nonewline $sock $packet
+        flush $sock
+        close $sock
+
+        wait_for_log_messages 0 \
+            [list "*Received invalid meet packet with 1 extensions but no 
extension data flag*"] \
+            $loglines 1000 10
+        assert_equal "PONG" [R 0 ping]
+    }
+
+    test "Reject cluster bus extensions shorter than their type requires" {
+        set base_port [srv 0 port]
+        set cluster_port [expr {$base_port + 10000}]
+        set sender_node_id [R 0 cluster myid]
+
+        foreach extension_type {0 1 2 3 4 5 6 7 8} {
+            set packet [create_cluster_meet_packet \
+                $sender_node_id $base_port $cluster_port 0 1 4]
+
+            # Append only the common eight-byte extension header. Every known
+            # extension type requires an additional data payload.
+            append packet [binary format I 8]
+            append packet [binary format S $extension_type]
+            append packet [binary format S 0]
+            set packet [string replace $packet 4 7 [binary format I [string 
length $packet]]]
+
+            set loglines [count_log_lines 0]
+            set sock [socket 127.0.0.1 $cluster_port]
+            fconfigure $sock -translation binary -buffering none -blocking 1
+            puts -nonewline $sock $packet
+            flush $sock
+            close $sock
+
+            wait_for_log_messages 0 \
+                [list "*Received invalid meet packet with extension type 
$extension_type that is 8 bytes*"] \
+                $loglines 1000 10
+            assert_equal "PONG" [R 0 ping]
+        }
+    }
+
+    test "Accept header-only unknown cluster bus extensions" {
+        set base_port [srv 0 port]
+        set cluster_port [expr {$base_port + 10000}]
+        set sender_node_id [R 0 cluster myid]
+
+        set packet [create_cluster_meet_packet \
+            $sender_node_id $base_port $cluster_port 0 1 4]
+        append packet [binary format I 8]
+        append packet [binary format S 10]
+        append packet [binary format S 0]
+        set packet [string replace $packet 4 7 [binary format I [string length 
$packet]]]
+
+        set loglines [count_log_lines 0]
+        set sock [socket 127.0.0.1 $cluster_port]
+        fconfigure $sock -translation binary -buffering none -blocking 1
+        puts -nonewline $sock $packet
+        flush $sock
+        close $sock
+
+        wait_for_log_messages 0 [list "*Received unknown extension type 10*"] 
$loglines 1000 10
+        assert_equal "PONG" [R 0 ping]
+    }
+
+    test "Reject unterminated string extensions in cluster bus packets" {
+        set base_port [srv 0 port]
+        set cluster_port [expr {$base_port + 10000}]
+        set sender_node_id [R 0 cluster myid]
+
+        foreach extension_type {0 1 4 5 8} {
+            set packet [create_cluster_meet_packet \
+                $sender_node_id $base_port $cluster_port 0 1 4]
+
+            # Append an aligned 16-byte string extension whose eight data bytes
+            # contain no NUL terminator.
+            append packet [binary format I 16]
+            append packet [binary format S $extension_type]
+            append packet [binary format S 0]
+            append packet "abcdefgh"
+            set packet [string replace $packet 4 7 [binary format I [string 
length $packet]]]
+
+            set loglines [count_log_lines 0]
+            set sock [socket 127.0.0.1 $cluster_port]
+            fconfigure $sock -translation binary -buffering none -blocking 1
+            puts -nonewline $sock $packet
+            flush $sock
+            close $sock
+
+            wait_for_log_messages 0 \
+                [list "*Received invalid meet packet with unterminated string 
extension type $extension_type*"] \
+                $loglines 1000 10
+            assert_equal "PONG" [R 0 ping]
+        }
+    }
+}
+
 start_cluster 1 0 {tags {external:skip cluster tls:skip}} {
     test "Packet with missing gossip messages don't cause invalid read" {
         set base_port [srv 0 port]

Reply via email to