Unbounded transaction reference validation
Description
The kernel's check_references()
function processes a transaction's reference addresses without enforcing any limit on their quantity. While transactions are bounded by a 1MB size limit, this still allows for approximately 34,000 references to be processed in a single transaction:
fn check_references(
&mut self,
callback: &mut M,
references: &IndexSet<Reference>,
) -> Result<(IndexSet<GlobalAddress>, IndexSet<InternalAddress>), BootloadingError> {
let mut global_addresses = indexset!();
let mut direct_accesses = indexset!();
// Unbounded iteration over references
for reference in references.iter() {
let node_id = &reference.0;
if ALWAYS_VISIBLE_GLOBAL_NODES.contains(node_id) {
continue;
}
// ... reference validation logic ...
}
Ok((global_addresses, direct_accesses))
}
Every reference requires the following:
Checking against always visible nodes
Validating the reference type
Reading substate information
Verifying the reference value
Adding to appropriate collections
Impact
Processing large numbers of references could increase block processing time as each reference requires substate reads and validation, add computational overhead during transaction validation, and potentially affect block-generation timing if transactions with many references are included.
The practical impact is low because the 1MB size limit provides an upper bound on the number of references that can be included in a single transaction.
Recommendations
We recommend enforcing a limit on the number of references that can be included in a transaction.
// @ radix-common/src/constants/transaction_execution.rs
pub const MAX_TRANSACTION_REFERENCES: usize = 1024;
fn check_references(
&mut self,
callback: &mut M,
references: &IndexSet<Reference>,
) -> Result<(IndexSet<GlobalAddress>, IndexSet<InternalAddress>), BootloadingError> {
if references.len() > MAX_TRANSACTION_REFERENCES {
return Err(BootloadingError::TooManyReferences(references.len()));
}
// ... existing validation logic ...
}
Remediation
This issue has been acknowledged by Radix Publishing Limited, and a fix was implemented in commit ea2ff3c2↗.