This commit is contained in:
Slavomir Kaslev 2026-05-28 10:50:32 +03:00 committed by GitHub
commit 2f89e95ebd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 92 additions and 1 deletions

View file

@ -2715,7 +2715,9 @@ void clusterProcessPingExtensions(clusterMsg *hdr, clusterLink *link) {
ext_shardid = shardid_ext->shard_id;
} else if (type == CLUSTERMSG_EXT_TYPE_INTERNALSECRET) {
clusterMsgPingExtInternalSecret *internal_secret_ext = (clusterMsgPingExtInternalSecret *) &(ext->ext[0].internal_secret);
if (memcmp(server.cluster->internal_secret, internal_secret_ext->internal_secret, CLUSTER_INTERNALSECRETLEN) > 0 ) {
if (!link->inbound && link->node && !nodeInHandshake(link->node) &&
memcmp(server.cluster->internal_secret, internal_secret_ext->internal_secret, CLUSTER_INTERNALSECRETLEN) > 0)
{
memcpy(server.cluster->internal_secret, internal_secret_ext->internal_secret, CLUSTER_INTERNALSECRETLEN);
}
} else {

View file

@ -15,6 +15,65 @@ proc wait_for_secret_sync {maxtries delay num_nodes} {
}
}
# Build a raw cluster bus PING packet with an INTERNALSECRET extension.
# sender_name: 40-char hex node ID to spoof as the sender.
# secret: 40-byte binary string to inject as the internal secret.
# client_port: the client port to announce.
proc build_cluster_bus_ping_with_secret {sender_name secret client_port} {
set CLUSTER_NAMELEN 40
set CLUSTER_SLOTS 16384
set NET_IP_STR_LEN 46
set CLUSTERMSG_TYPE_PING 0
set CLUSTERMSG_EXT_TYPE_INTERNALSECRET 4
set CLUSTERMSG_FLAG0_EXT_DATA 4
set CLUSTER_INTERNALSECRETLEN 40
# Extension: length(4) + type(2) + unused(2) + secret(40) = 48 bytes
set ext_len 48
set ext [binary format ISS $ext_len $CLUSTERMSG_EXT_TYPE_INTERNALSECRET 0]
append ext $secret
set base_header_size 2256
set totlen [expr {$base_header_size + $ext_len}]
set cport [expr {$client_port + 10000}]
# Pad sender to CLUSTER_NAMELEN
set sender_padded [binary format a${CLUSTER_NAMELEN} $sender_name]
# Build header fields up to the data section
set hdr {}
append hdr "RCmb"
append hdr [binary format I $totlen]
append hdr [binary format S 1] ;# ver
append hdr [binary format S $client_port] ;# port
append hdr [binary format S $CLUSTERMSG_TYPE_PING] ;# type
append hdr [binary format S 0] ;# count (0 gossip entries)
append hdr [binary format W 0] ;# currentEpoch
append hdr [binary format W 0] ;# configEpoch
append hdr [binary format W 0] ;# offset
append hdr $sender_padded ;# sender
append hdr [string repeat "\x00" [expr {$CLUSTER_SLOTS / 8}]] ;# myslots
append hdr [string repeat "\x00" $CLUSTER_NAMELEN] ;# slaveof
set myip [binary format a${NET_IP_STR_LEN} "127.0.0.1"]
append hdr $myip ;# myip
append hdr [binary format S 1] ;# extensions count
append hdr [string repeat "\x00" 30] ;# notused1
append hdr [binary format S 0] ;# pport
append hdr [binary format S $cport] ;# cport
append hdr [binary format S 1] ;# flags (CLUSTER_NODE_MASTER)
append hdr [binary format c 0] ;# state
append hdr [binary format ccc $CLUSTERMSG_FLAG0_EXT_DATA 0 0] ;# mflags
# Pad to base_header_size
set cur_len [string length $hdr]
if {$cur_len < $base_header_size} {
append hdr [string repeat "\x00" [expr {$base_header_size - $cur_len}]]
}
append hdr $ext
return $hdr
}
start_cluster 3 3 {tags {external:skip cluster}} {
test "Test internal secret sync" {
wait_for_secret_sync 50 100 6
@ -69,3 +128,33 @@ start_cluster 3 3 {tags {external:skip cluster}} {
}
}
}
start_cluster 1 0 {tags {external:skip cluster}} {
test "Inbound cluster bus connection cannot inject a forged internal secret" {
set host [srv 0 host]
set port [srv 0 port]
set cport [expr {$port + 10000}]
set node_id [R 0 CLUSTER MYID]
set secret_before [R 0 debug internal_secret]
# Open a raw TCP socket to the cluster bus and send a forged PING
# spoofing the server's own node name, with a zero-byte secret that
# would win the lexicographic comparison against any real secret.
set zero_secret [string repeat "\x00" 40]
set pkt [build_cluster_bus_ping_with_secret $node_id $zero_secret $port]
set fd [socket $host $cport]
fconfigure $fd -translation binary -buffering full
puts -nonewline $fd $pkt
flush $fd
after 500
close $fd
# The internal secret must not have changed.
set secret_after [R 0 debug internal_secret]
assert_equal $secret_before $secret_after
# AUTH with the forged zero-byte secret must be rejected.
assert_error {*WRONGPASS*} {R 0 auth "internal connection" $zero_secret}
}
}