fix(consensus): clamp commitment debug logging to bitset size#7366
fix(consensus): clamp commitment debug logging to bitset size#7366thepastaclaw wants to merge 1 commit into
Conversation
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
Walkthrough
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
✅ Review complete (commit e862f6b) |
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
PR clamps the only pre-validation validMembers[i] access in CheckLLMQCommitment()'s debug-log loop to the deserialized bitset size, eliminating the OOB read on malformed commitments while leaving the existing VerifySizes() rejection path intact. The other debug-log loop in CFinalCommitment::Verify() is already protected by a preceding VerifySizes() check, so the PR's scope is complete. Regression test pins the fix.
✅ Verified clean. GitHub does not allow PastaClaw to approve its own PR, so this is posted as a comment review rather than an approval.
CheckLLMQCommitment indexed qcTx.commitment.validMembers[i] in a for-loop over llmq_params.size before Verify() runs VerifySizes(). signers and validMembers are DYNBITSET wire fields and can deserialize smaller than llmq_params.size, so with -debug=llmq a malformed mined commitment could trigger an out-of-bounds read prior to normal validation rejecting it. Quorum commitment txs are not mempool-accepted so practical exploitability is capped, but the debug-log path should not invoke UB. Clamp the loop bound to min(llmq_params.size, validMembers.size()); VerifySizes() still rejects the size mismatch immediately after. Add a regression test that drives CheckLLMQCommitment directly with an empty validMembers DYNBITSET while LLMQ debug logging is enabled, captures emitted log lines via LogInstance().PushBackCallback (cleanup guarded by RAII so a BOOST_REQUIRE failure does not leak the callback or category state), and asserts the debug line renders 'validMembers[]' and contains no 'v[0]' entry. The check pins the regression to log contents rather than relying on sanitizer- or platform-specific UB behaviour on std::vector<bool>. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
e862f6b
b18e7e2 to
e862f6b
Compare
PastaPastaPasta
left a comment
There was a problem hiding this comment.
utACK; assuming CI is happy
✅ No Merge Conflicts DetectedThis PR currently has no conflicts with other open PRs. |
|
This pull request has conflicts, please rebase. |
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Tightly scoped, correct fix: clamps the pre-validation debug-log loop in CheckLLMQCommitment to min(llmq_params.size, validMembers.size()), preventing an OOB read on malformed wire-format DYNBITSET payloads when -debug=llmq is enabled. Validation semantics are unchanged because Verify()/VerifyNull() still reject mismatched sizes via VerifySizes(). The regression test correctly exercises the OOB-prone path by forcing failure on bad-qc-height so the debug log is emitted, then asserts clamped output via a RAII-guarded log callback. Reconciliation: carried-forward prior findings: none (prior PastaClaw review at b18e7e2 found nothing); new findings in latest delta: 0 — the e862f6b delta only adds the #include <algorithm> required by std::min<size_t>. CodeRabbit reported 0 inline findings. GitHub does not allow PastaClaw to approve its own PR, so this verified-clean result is posted as a comment review rather than an approval.
|
CI note: the red |
Issue being fixed or feature implemented
CheckLLMQCommitment()logsvalidMembersbeforeCFinalCommitment::Verify()validates the deserialized bitset sizes. Amalformed quorum commitment payload can provide a valid LLMQ type while
encoding an undersized
validMembersbitset, causing the debug log loop toindex past the deserialized vector.
Practical exploitability is low because quorum-commitment transactions are not
accepted from the mempool, and this path requires both a mined malformed block
and non-default
-debug=llmqlogging. This is still consensus/security-adjacenthardening because validation should reject the malformed payload without
invoking undefined behavior in debug logging.
What was done?
CheckLLMQCommitment()debug-log loop to the smallerof the configured LLMQ size and the deserialized
validMemberssize.still rejected by
VerifySizes().CheckLLMQCommitment()with anundersized
validMembersbitset while LLMQ debug logging is enabled.How Has This Been Tested?
Tested on macOS arm64 in a local Dash Core depends build:
make -j6 -C src test/test_dashsrc/test/test_dash --run_test=llmq_commitment_testsThe regression test was also checked against the old unclamped loop after
rebuilding the affected test binary; it crashes on the out-of-bounds debug-log
access before this fix and passes with the clamp.
Breaking Changes
None. Valid commitment validation is unchanged; malformed commitments continue
to be rejected by the existing size checks.
Checklist: