#41516 [BC-High] The attacker exceeds the number of transactions TOO_NEW_TOLERANCE and performs a DoS attack.
Description
Brief/Intro
Vulnerability Details
fn has_invalid_sequence_number(
&self,
transaction: &SignedTransaction,
) -> Result<SequenceNumberValidity, Error> {
// check against the used sequence number pool
-> let used_sequence_number = self
.used_sequence_number_pool
.get_sequence_number(&transaction.sender())
.unwrap_or(0);
// validate against the state view
let state_view = self.db_reader.latest_state_checkpoint_view().map_err(|e| {
Error::InternalError(format!("Failed to get latest state view: {:?}", e))
})?;
// this checks that the sequence number is too old or too new
let committed_sequence_number =
vm_validator::get_account_sequence_number(&state_view, transaction.sender())?;
debug!(
"Used sequence number: {:?} Committed sequence number: {:?}",
used_sequence_number, committed_sequence_number
);
let min_used_sequence_number =
-> if used_sequence_number > 0 { used_sequence_number + 1 } else { 0 };
let min_sequence_number = (min_used_sequence_number).max(committed_sequence_number);
let max_sequence_number = committed_sequence_number + TOO_NEW_TOLERANCE;
......
}
async fn submit_transaction(
&mut self,
transaction: SignedTransaction,
) -> Result<SubmissionStatus, Error> {
......
// Pre-execute Tx to validate its content.
// Re-create the validator for each Tx because it uses a frozen version of the ledger.
let vm_validator = VMValidator::new(Arc::clone(&self.db_reader));
let tx_result = vm_validator.validate_transaction(transaction.clone())?;
// invert the application priority with the u64 max minus the score from aptos (which is high to low)
let application_priority = u64::MAX - tx_result.score(); //@audit 攻击者传入错误的 tx_result.score 会导致循环退出?
match tx_result.status() {
Some(_) => {
let ms = MempoolStatus::new(MempoolStatusCode::VmError);
debug!("Transaction not accepted: {:?}", tx_result.status());
return Ok((ms, tx_result.status()));
}
None => {
debug!("Transaction accepted by VM: {:?}", transaction);
}
}
// has_invalid_sequence_number -> committed_sequence_number
// sequence_number = committed_sequence_number
-> let sequence_number = match self.has_invalid_sequence_number(&transaction)? {
SequenceNumberValidity::Valid(sequence_number) => sequence_number,
SequenceNumberValidity::Invalid(status) => {
return Ok(status);
}
};
// Add the txn for future validation
debug!("Adding transaction to mempool: {:?} {:?}", transaction, sequence_number);
let status = self.core_mempool.add_txn(
transaction.clone(),
0,
sequence_number,
TimelineState::NonQualified,
true,
);
match status.code {
MempoolStatusCode::Accepted => {
let now = chrono::Utc::now().timestamp_millis() as u64;
debug!("Transaction accepted: {:?}", transaction);
let sender = transaction.sender();
-> let transaction_sequence_number = transaction.sequence_number();
self.transaction_sender
.send((application_priority, transaction))
.await
.map_err(|e| anyhow::anyhow!("Error sending transaction: {:?}", e))?;
// increment transactions in flight
{
let mut transactions_in_flight = self.transactions_in_flight.write().unwrap();
transactions_in_flight.increment(now, 1);
}
self.core_mempool.commit_transaction(&sender, sequence_number);
// update the used sequence number pool
info!(
"Setting used sequence number for {:?} to {:?}",
sender, transaction_sequence_number
);
-> self.used_sequence_number_pool.set_sequence_number(
&sender,
transaction_sequence_number,
now,
);
}
_ => {
warn!("Transaction not accepted: {:?}", status);
}
}
// report status
Ok((status, None))
}
}
Impact Details
References
Proof of Concept
Proof of Concept
Previous#41489 [BC-Critical] Blob sizes remain unchecked leading to chain haltNext#41518 [BC-High] The transaction to modify the gas price was not processed.
Was this helpful?