Skip to content

Add CRC32 integrity check for cluster bus messages#4201

Open
enjoy-binbin wants to merge 3 commits into
valkey-io:unstablefrom
enjoy-binbin:cluster_crc
Open

Add CRC32 integrity check for cluster bus messages#4201
enjoy-binbin wants to merge 3 commits into
valkey-io:unstablefrom
enjoy-binbin:cluster_crc

Conversation

@enjoy-binbin

Copy link
Copy Markdown
Member

The cluster bus only checks the magic string and length, so
a corrupted gossip message (e.g. a bit flip from NIC/switch
faults) is still accepted. The receiver then updates cluster
metadata from the bad data: a wrong configEpoch (the rule is
max(new, old), so a larger bogus value can never be corrected
and scrambles slot ownership), a phantom node created from a
corrupted nodename, or an inconsistent slot bitmap.

Add a uint32_t crc field to the message header holding a CRC32
of the whole message, computed by the sender and verified by
the receiver. When the field is 0 the sender has CRC disabled,
so the receiver skips the check; old nodes never set the field,
giving the same effect and keeping mixed/old peers compatible.

When the CRC check fails, the receiver discards the packet. It
should be noted that if the receiver consistently discards packets,
the node may enter the PFAIL/FAIL state.

The check is gated by the new cluster-crc-enabled configuration,
the default is no. If disabled, no CRC check will be performed.

The CRC seed is derived from requirepass, so only nodes with the
same password verify, which also isolates distinct clusters.

New CLUSTER INFO field: cluster_stats_messages_crc_mismatch.
New DEBUG cluster-crc-flip-bit / cluster-crc-flip-time commands.

The cluster bus only checks the magic string and length, so
a corrupted gossip message (e.g. a bit flip from NIC/switch
faults) is still accepted. The receiver then updates cluster
metadata from the bad data: a wrong configEpoch (the rule is
max(new, old), so a larger bogus value can never be corrected
and scrambles slot ownership), a phantom node created from a
corrupted nodename, or an inconsistent slot bitmap.

Add a uint32_t crc field to the message header holding a CRC32
of the whole message, computed by the sender and verified by
the receiver. When the field is 0 the sender has CRC disabled,
so the receiver skips the check; old nodes never set the field,
giving the same effect and keeping mixed/old peers compatible.

When the CRC check fails, the receiver discards the packet. It
should be noted that if the receiver consistently discards packets,
the node may enter the PFAIL/FAIL state.

The check is gated by the new cluster-crc-enabled configuration,
the default is no. If disabled, no CRC check will be performed.

The CRC seed is derived from requirepass, so only nodes with the
same password verify, which also isolates distinct clusters.

New CLUSTER INFO field: cluster_stats_messages_crc_mismatch.
New DEBUG cluster-crc-flip-bit / cluster-crc-flip-time commands.

Signed-off-by: Binbin <binloveplay1314@qq.com>
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 08e9dac0-55df-481e-bcfa-3db41923706b

📥 Commits

Reviewing files that changed from the base of the PR and between 6e8fa3a and 7d482ae.

📒 Files selected for processing (1)
  • src/cluster_legacy.c
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/cluster_legacy.c

📝 Walkthrough

Walkthrough

Changes

Cluster bus messages now support optional CRC32 checksums. The protocol layout, checksum implementation, build wiring, configuration, send/receive validation, mismatch statistics, and DEBUG fault-injection controls are updated.

Cluster CRC32 support

Layer / File(s) Summary
CRC32 protocol and build foundation
src/cluster_legacy.h, src/crc32.c, src/server.h, src/config.c, cmake/Modules/SourceFiles.cmake, src/Makefile
Adds the cluster message CRC field, CRC32 implementation, server state, configuration, and build inputs.
Cluster message CRC flow
src/cluster_legacy.c, src/cluster.c
Computes CRCs for outgoing full-header messages, validates incoming messages, tracks mismatches, resets the counter, and reports the statistic.
CRC fault injection controls
src/debug.c, src/server.c
Adds DEBUG commands for fixed-bit and time-bounded CRC corruption and initializes their server state.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant clusterSendMessage
  participant clusterMsgFinalizeCRC
  participant crc32
  participant clusterIsValidPacket
  participant clusterState
  clusterSendMessage->>clusterMsgFinalizeCRC: finalize full-header message
  clusterMsgFinalizeCRC->>crc32: compute seeded CRC32
  crc32-->>clusterMsgFinalizeCRC: return checksum
  clusterMsgFinalizeCRC-->>clusterSendMessage: send message with CRC
  clusterIsValidPacket->>crc32: verify received CRC32
  crc32-->>clusterIsValidPacket: return checksum
  clusterIsValidPacket->>clusterState: increment mismatch counter on failure
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding CRC32 integrity checks to cluster bus messages.
Description check ✅ Passed The description is directly related to the change set and correctly describes the CRC32 cluster-message update.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cluster_legacy.c`:
- Around line 3941-3945: Update the CRC validation path in clusterMsgVerifyCRC,
before any access or modification of hdr->crc, to verify that the received
packet length is large enough to contain the CRC field at its defined offset.
Reject undersized or unrecognized packets without performing CRC verification,
while preserving normal verification for sufficiently large packets.

In `@src/debug.c`:
- Around line 655-657: Update the cluster-crc-flip-bit branch in the debug
command handler to parse its argument with getLongFromObjectOrReply() instead of
atoi, propagating a reply on invalid or out-of-range input and assigning the
validated result to server.debug_cluster_crc_flip_bit. Match the existing
CLUSTER-CRC-FLIP-TIME implementation’s parsing behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 79ac1c9f-fba1-48a6-aa26-238a1381a09a

📥 Commits

Reviewing files that changed from the base of the PR and between 6b006c9 and 0bb1f48.

📒 Files selected for processing (10)
  • cmake/Modules/SourceFiles.cmake
  • src/Makefile
  • src/cluster.c
  • src/cluster_legacy.c
  • src/cluster_legacy.h
  • src/config.c
  • src/crc32.c
  • src/debug.c
  • src/server.c
  • src/server.h

Comment thread src/cluster_legacy.c
Comment thread src/debug.c
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 13.69863% with 63 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.80%. Comparing base (6b006c9) to head (7d482ae).

Files with missing lines Patch % Lines
src/cluster_legacy.c 8.92% 51 Missing ⚠️
src/debug.c 22.22% 7 Missing ⚠️
src/crc32.c 0.00% 5 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #4201      +/-   ##
============================================
- Coverage     76.81%   76.80%   -0.01%     
============================================
  Files           162      163       +1     
  Lines         81455    81527      +72     
============================================
+ Hits          62570    62618      +48     
- Misses        18885    18909      +24     
Files with missing lines Coverage Δ
src/cluster.c 92.43% <100.00%> (+<0.01%) ⬆️
src/config.c 79.85% <ø> (ø)
src/server.c 89.46% <100.00%> (-0.05%) ⬇️
src/server.h 100.00% <ø> (ø)
src/crc32.c 0.00% <0.00%> (ø)
src/debug.c 55.52% <22.22%> (-0.26%) ⬇️
src/cluster_legacy.c 86.89% <8.92%> (-1.32%) ⬇️

... and 13 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Signed-off-by: Binbin <binloveplay1314@qq.com>

@valkey-review-bot valkey-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found one compatibility issue in the CRC seed choice.

Comment thread src/cluster_legacy.c
static uint32_t clusterCrcSeed(void) {
if (server.requirepass == NULL || sdslen(server.requirepass) == 0) return 0;

return crc32(0, (const unsigned char *)server.requirepass, sdslen(server.requirepass));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server.requirepass is not a stable cluster-wide secret. It is a per-node, modifiable ACL setting (src/config.c:3428-3429, src/server.h:2344-2346), and the cluster bus itself just connects and sends PING/MEET without any password negotiation (src/cluster_legacy.c:4711-4733, src/cluster_legacy.c:6308-6323). Using it as the CRC seed means a normal rolling CONFIG SET requirepass changes the seed on one node immediately, so once cluster-crc-enabled is on that node starts rejecting full-header packets from peers that have not been updated yet and can drive the cluster into PFAIL/FAIL. The seed needs to come from a dedicated cluster-wide secret/capability, or the CRC should stay unkeyed.

This reverts commit 6e8fa3a.
See isClusterMsgSignatureAndLengthValid.

Signed-off-by: Binbin <binloveplay1314@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant