Security: Replace queued checkpoint blocks with duplicate hashes (#2697)

We don't check the authorizing data hash until checkpoint blocks reach the state.

So signatures, proofs, or scripts could be different,
even if the block hash is the same.

Co-authored-by: Conrado Gouvea <conrado@zfnd.org>
This commit is contained in:
teor 2021-09-01 02:50:47 +10:00 committed by GitHub
parent 8bff71e857
commit 34c7a27c2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 13 additions and 3 deletions

View File

@ -539,13 +539,23 @@ where
.entry(height)
.or_insert_with(|| QueuedBlockList::with_capacity(1));
// Replace older requests by newer ones by swapping the oneshot.
// Replace older requests with newer ones.
// The newer block is ok, the older block is an error.
for qb in qblocks.iter_mut() {
if qb.block.hash == hash {
let e = VerifyCheckpointError::NewerRequest { height, hash };
tracing::trace!(?e, "failing older of duplicate requests");
let old_tx = std::mem::replace(&mut qb.tx, new_qblock.tx);
let _ = old_tx.send(Err(e));
// ## Security
//
// Replace the entire queued block.
//
// We don't check the authorizing data hash until checkpoint blocks reach the state.
// So signatures, proofs, or scripts could be different,
// even if the block hash is the same.
let old = std::mem::replace(qb, new_qblock);
let _ = old.tx.send(Err(e));
return Ok(req_block);
}
}