Skip to content

[RWF] messages-relay: selected range overflows near maximum nonce #12722

Description

@xlc

Summary

When the selected range begins at MessageNonce::MAX, the expression
begin + count - 1 performs the overflowing MAX + 1 intermediate calculation in
debug builds instead of returning the valid range MAX..=MAX.

This finding was found by Runtime Whitebox Fuzzer.

Severity / Sensitivity

Low severity, non-sensitive. This is a public boundary arithmetic defect in message-range construction.

Source Evidence

  • bridges/relays/messages/src/message_race_limits.rs:78-81: best_target_nonce = MAX - 1 produces a valid begin nonce of MAX.
  • bridges/relays/messages/src/message_race_limits.rs:165-168: range-end arithmetic then overflows.

PoC Unit Test

Place this in bridges/relays/messages/src/generated_tests.rs. The helper is
repeated so this PoC can be pasted independently of finding 4.

use super::*;
use bp_messages::{MessageNonce, Weight};
use crate::message_lane_loop::{MessageDetails, MessageDetailsMap};
use crate::message_lane_loop::tests::{header_id, TestMessageLane};
use crate::message_race_limits::{MessageRaceLimits, RelayMessagesBatchReference};

fn single_max_nonce_reference() -> RelayMessagesBatchReference<TestMessageLane> {
	let mut details = MessageDetailsMap::new();
	details.insert(
		MessageNonce::MAX,
		MessageDetails { dispatch_weight: Weight::from_parts(1, 0), size: 1, reward: 0 },
	);
	RelayMessagesBatchReference::<TestMessageLane> {
		max_messages_in_this_batch: 10,
		max_messages_weight_in_single_batch: Weight::from_parts(100, 0),
		max_messages_size_in_single_batch: 1_000,
		best_target_nonce: MessageNonce::MAX - 1,
		nonces_queue: vec![(header_id(1), details)].into_iter().collect(),
		nonces_queue_range: 0..=0,
	}
}

// RWF-INVARIANTS: inv_wu594hra
// RWF-RISKS: risk_yq5p6bas
#[ignore]
#[tokio::test]
async fn test_inv_wu594hra_decide_single_message_near_max_boundary() {
	let range = MessageRaceLimits::decide(single_max_nonce_reference())
		.await
		.expect("the single MAX nonce message must be deliverable");
	assert_eq!(*range.start(), MessageNonce::MAX);
	assert_eq!(*range.end(), MessageNonce::MAX);
}

Reproduction Command

cargo test -p messages-relay \
  generated_tests::test_inv_wu594hra_decide_single_message_near_max_boundary \
  -- --ignored --exact --nocapture

Observed Result

panicked at bridges/relays/messages/src/message_race_limits.rs:167:17:
attempt to add with overflow

Expected Behavior

Return the single-message range MessageNonce::MAX..=MessageNonce::MAX without an
overflowing intermediate calculation.

Likely Fix Direction

Compute the inclusive range end without an overflowing intermediate, using checked arithmetic and preserving the valid MAX..=MAX case.

RWF Metadata

  • Found by Runtime Whitebox Fuzzer

  • Finding: find_5wqne5x69x

  • Target: messages-relay

  • Severity: low

  • Category: arithmetic overflow

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions