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

Stop untrusted preallocation during deserialization #1925

Merged
merged 9 commits into from
Mar 22, 2021

Conversation

teor2345
Copy link
Contributor

@teor2345 teor2345 commented Mar 19, 2021

Motivation

Zebra believes untrusted lengths when deserializing, and preallocates a Vec based on that size:

  • JoinSplit list size field
  • String sizes
  • Script sizes

This is trivial a memory exhaustion attack.

Zebra also uses Read::take in risky ways. The old code was correct, but copying it elsewhere could have hidden short reads.

Solution

  • use the current auto-growing Vec deserialize implementation, which is limited by the size of the message data
  • replace Read::take with validated Vec preallocation

The code in this pull request has:

  • Documentation Comments
  • Existing Unit Tests and Property Tests

Review

@dconnolly or @oxarbitrage this fix is urgent, but not critical, because it's only a local memory denial of service.

Related Issues

Blocks #1920, this fix will cause #1920 to fail due to a missing trusted preallocation impl for the listed types

Follow Up Work

Trusted vector preallocation #1920

@teor2345 teor2345 added C-bug Category: This is a bug A-rust Area: Updates to Rust code P-High C-security Category: Security issues I-panic Zebra panics with an internal error message I-heavy Problems with excessive memory, disk, or CPU usage I-unbounded-growth Zebra keeps using resources, without any limit I-invalid-data Zebra relies on invalid or untrusted data, or sends invalid data labels Mar 19, 2021
@teor2345 teor2345 added this to the 2021 Sprint 5 milestone Mar 19, 2021
@teor2345 teor2345 self-assigned this Mar 19, 2021
Zebra believes the untrusted `JoinSplit` list size field when
deserializing `JoinSplit`s, and preallocates a `Vec` based on that size.

This is trivial a memory exhaustion attack.

Instead, use the current auto-growing implementation, which is limited
by the size of the message data.
This is an easy memory denial of service attack.
This is an easy memory denial of service attack.
@teor2345 teor2345 force-pushed the joinsplit-memory-dos branch from e763ea3 to 473a042 Compare March 19, 2021 07:59
@teor2345 teor2345 changed the title Stop unsafe preallocation during JoinSplit deserialization Stop unsafe preallocation during deserialization Mar 19, 2021
@teor2345
Copy link
Contributor Author

I also found similar security issues in Script and String deserialization.

Zebra already uses `Read::take` to enforce message, body, and block
maximum sizes.

So using `Read::take` on untrusted sizes can result in short reads,
without a corresponding `UnexpectedEof` error. (The old code was
correct, but copying it elsewhere would have been risky.)
@teor2345
Copy link
Contributor Author

I also found some risky uses of Read::take, so I replaced them with validated Vec preallocation.

teor2345 and others added 2 commits March 22, 2021 07:58
Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>
@teor2345 teor2345 requested a review from oxarbitrage March 21, 2021 21:59
@teor2345 teor2345 changed the title Stop unsafe preallocation during deserialization Stop untrusted preallocation during deserialization Mar 22, 2021
dconnolly
dconnolly previously approved these changes Mar 22, 2021
@dconnolly dconnolly merged commit c5b1d0d into ZcashFoundation:main Mar 22, 2021
@dconnolly dconnolly mentioned this pull request Mar 23, 2021
23 tasks
dconnolly added a commit that referenced this pull request Mar 23, 2021
Zebra's latest alpha checkpoints on Canopy activation, continues our work on NU5, and fixes a security issue.

Some notable changes include:

## Added
- Log address book metrics when PeerSet or CandidateSet don't have many peers (#1906)
- Document test coverage workflow (#1919)
- Add a final job to CI, so we can easily require all the CI jobs to pass (#1927)

## Changed
- Zebra has moved its mandatory checkpoint from Sapling to Canopy (#1898, #1926)
  - This is a breaking change for users that depend on the exact height of the mandatory checkpoint.

## Fixed
- tower-batch: wake waiting workers on close to avoid hangs (#1908)
- Assert that pre-Canopy blocks use checkpointing (#1909)
- Fix CI disk space usage by disabling incremental compilation in coverage builds (#1923)

## Security
- Stop relying on unchecked length fields when preallocating vectors (#1925)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-rust Area: Updates to Rust code C-bug Category: This is a bug C-security Category: Security issues I-heavy Problems with excessive memory, disk, or CPU usage I-invalid-data Zebra relies on invalid or untrusted data, or sends invalid data I-panic Zebra panics with an internal error message I-unbounded-growth Zebra keeps using resources, without any limit
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants