Skip to content

Musitdev/prevent untrusted memory allocation - #373

Open
musitdev wants to merge 6 commits into
m1from
musitdev/prevent_untrusted_memory_allocation
Open

Musitdev/prevent untrusted memory allocation#373
musitdev wants to merge 6 commits into
m1from
musitdev/prevent_untrusted_memory_allocation

Conversation

@musitdev

@musitdev musitdev commented Jun 2, 2026

Copy link
Copy Markdown

Description

Reimplementation of this PR fix
Correct an unbounded heap allocation from untrusted wire field in PROXY protocol parser.

How Has This Been Tested?

Key Areas to Review

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Performance improvement
  • Refactoring
  • Dependency update
  • Documentation update
  • Tests

Which Components or Systems Does This Change Impact?

  • Validator Node
  • Full Node (API, Indexer, etc.)
  • Move/Aptos Virtual Machine
  • Aptos Framework
  • Aptos CLI/SDK
  • Developer Infrastructure
  • Move Compiler
  • Other (specify)

Checklist

  • I have read and followed the CONTRIBUTING doc
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I identified and added all stakeholders and component owners affected by this change as reviewers
  • I tested both happy and unhappy path of the functionality
  • I have made corresponding changes to the documentation

musitdev added 3 commits May 27, 2026 15:13
…om untrusted length field

- add GuardedReadStream wrapper that fails if any single read request exceeds a configurable bound
- verify that a PROXY v2 header declaring address_size=u16::MAX never triggers a read larger than the bound
…ize reads and unified drain

- determine bytes to parse upfront from the protocol family (compile-time constant, never the wire value)
- read only that fixed portion into a stack buffer; parse the result after the stream is fully consumed
- drain all remaining declared bytes in a single bounded loop, covering every branch uniformly
@musitdev musitdev self-assigned this Jun 2, 2026

@seanyoung seanyoung left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Some suggestions but looks good to merge

Comment thread network/netcore/src/transport/proxy_protocol.rs
Comment on lines +103 to +113
// Drain whatever the sender declared beyond what we parsed, in bounded chunks.
// This single drain covers every branch: LOCAL/UDP/UNIX (all bytes), IPv4/IPv6
// with exact size (zero bytes), IPv4/IPv6 with extra padding, and error cases.
let remaining = address_size.saturating_sub(fixed_parse_size);
let mut scratch = [0u8; 256];
let mut left = remaining as usize;
while left > 0 {
let take = left.min(scratch.len());
stream.read_exact(&mut scratch[..take]).await?;
left = left.saturating_sub(take);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

if someone is sending more data, they are likely trying to do something bad. Can't we just error out in this case? It will make the code much simpler.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Probably but it can be a bug in the address formatting and the rest of the stream is correct. In the protocol they allow more data in the address section. In Aptos they just throw it away I keep the same logic.

@seanyoung

Copy link
Copy Markdown
Collaborator

I have a question.

The most an attacker can allocate is 64KiB. That's not very much at all and I don't understand how that could be abused. Is this change worthwhile?

@musitdev

Copy link
Copy Markdown
Author

Why is the allocation limited to 64KB ? The size is defined in the message, and the old code does the allocation with the defined size. If an attacker put any big value in the message, with the old version, the code does the allocation.
This patch blocks this.

@seanyoung

Copy link
Copy Markdown
Collaborator

because address_size is u16:

    let address_size = u16::from_be_bytes(address_size);

    let mut address_bytes: Vec<u8> = vec![0; address_size as usize];

@musitdev

Copy link
Copy Markdown
Author

Ah yes, so the risk is more sort of dos attacks where several messages with 64k allocation are sent.
It's a bug corrected upstream, but we are not obliged to patch it. @rubujubi you decide to merge it or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants