Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(consensus): additional sanity checks for the size of proposed blocks #1408

Merged
merged 18 commits into from
Jan 26, 2024

Conversation

cason
Copy link
Contributor

@cason cason commented Sep 27, 2023

Hardens tests regarding the size of proposed blocks, namely:

  • The byte size of a proposal block Part should be constant (== types.BlockPartSizeBytes), except for the last part of a PartSet (<= types.BlockPartSizeBytes)
  • A valid Proposal should not enclose a PartSet enabling the building of a ProposalBlock with size larger than the configured ConsensusParams.Block.MaxBytes. Notice that building a ProposalBlock larger than the allowed would fail in any case, but the proposed changes also invalidate the associated Proposal.

PR checklist

  • Tests written/updated
  • Changelog entry added in .changelog (we use unclog to manage our changelog)
  • Updated relevant documentation (docs/ or spec/) and code comments

types/part_set.go Outdated Show resolved Hide resolved
types/part_set.go Outdated Show resolved Hide resolved
@cason cason marked this pull request as ready for review September 28, 2023 03:38
@cason cason requested review from a team as code owners September 28, 2023 03:38
return ErrPartTooBig
}
// All parts except the last one should have the same constant size.
if int64(part.Index) < part.Proof.Total-1 && len(part.Bytes) != int(BlockPartSizeBytes) {
Copy link
Contributor

@sergio-mena sergio-mena Sep 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're still using part.Proof.Total here, are we 100% sure this total will always be in sync with the total number of parts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a good point. But we don't have the Total field in each Part, we only have it on the PartSet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point here is that wrong values for Proof.Total and Proof.Index should make the Merkle-tree verification to fail. But I am not sure whether we test this at this point. Notice that the Part tests have nothing on the arrays used to fill the Part and the Part.Proof bytes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a possibility that Part is used without populating part.Proof? (I guess no, but double-checking).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not be possible, as the next check (line 40) would fail. This check, however, is also a valid check: integer fields are >= 0, hashes have the right length.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, status regarding this:

  • we can trust Proof.Index, as change it causes the proof verification to fail
  • we can't trust Proof.Total, as it is irrelevant for the proof verification provided that Proof.Index < Proof.Total.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, now Proof.Total should be correct, otherwise the Part is not added. Lets check if something breaks due to this additional check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent!

consensus/state.go Outdated Show resolved Hide resolved
Comment on lines 313 to 317
maxBlockParts := maxBytes / int64(types.BlockPartSizeBytes)
if maxBytes > maxBlockParts*int64(types.BlockPartSizeBytes) {
maxBlockParts += 1
}
numBlockParts := int64(propBlockParts.Total())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
maxBlockParts := maxBytes / int64(types.BlockPartSizeBytes)
if maxBytes > maxBlockParts*int64(types.BlockPartSizeBytes) {
maxBlockParts += 1
}
numBlockParts := int64(propBlockParts.Total())
maxBlockParts := (maxBytes-1) / int64(types.BlockPartSizeBytes) + 1
numBlockParts := int64(propBlockParts.Total())

How about this instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer using a different method, even if it is less efficient/smart, when testing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point

@github-actions
Copy link

github-actions bot commented Oct 9, 2023

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@github-actions github-actions bot added the stale For use by stalebot label Oct 9, 2023
@sergio-mena sergio-mena removed the stale For use by stalebot label Oct 10, 2023
Copy link
Contributor

@sergio-mena sergio-mena left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was convinced I had already approved this (sorry for delay)

@thanethomson
Copy link
Contributor

Is this going to be backported? If so, to which version(s)?

@cason
Copy link
Contributor Author

cason commented Oct 12, 2023

Is this going to be backported? If so, to which version(s)?

I would say all releases. Why?

@thanethomson
Copy link
Contributor

I would say all releases. Why?

There are currently no backport labels on the PR.

Let's get this over the finish line please.

@cason
Copy link
Contributor Author

cason commented Oct 12, 2023

There are currently no backport labels on the PR.

Sorry, my bad. @sergio-mena, can you confirm we are backporting this to all releases?

@sergio-mena
Copy link
Contributor

As this comes from our work in a security advisory, I'd say we should backport it to all releases

@cason cason self-assigned this Oct 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-to-v0.34.x Tell Mergify to backport the PR to v0.34.x backport-to-v0.37.x Tell Mergify to backport the PR to v0.37.x backport-to-v0.38.x Tell Mergify to backport the PR to v0.38.x backport-to-v1.x Tell Mergify to backport the PR to v1.x consensus wip Work in progress
Projects
No open projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

None yet

7 participants