pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/vortex-data/vortex/pull/9155

requests-12898a7be3dbcd40.css" /> fix(buffer): bound alignment exponents read from untrusted input by lorenzhs · Pull Request #9155 · vortex-data/vortex · GitHub
Skip to content

fix(buffer): bound alignment exponents read from untrusted input - #9155

Open
lorenzhs wants to merge 2 commits into
vortex-data:developfrom
lorenzhs:lorenz/bound-serialized-alignment-exponent
Open

fix(buffer): bound alignment exponents read from untrusted input#9155
lorenzhs wants to merge 2 commits into
vortex-data:developfrom
lorenzhs:lorenz/bound-serialized-alignment-exponent

Conversation

@lorenzhs

@lorenzhs lorenzhs commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Rationale for this change

Found a few places where untrusted alignments from input files are not properly validated and can lead to excessive allocation sizes / OOMs.

Alignments in the file format are a power-of-two exponent in a u8, and try_from_exponent only rejects exponents that would overflow a usize shift. Satisfying an alignment can require copying the buffer into an allocation of len + alignment bytes, so an exponent of 40 on a 4-byte buffer asks the reader for 1 TiB.

This cannot be contained by the caller: Rust aborts via handle_alloc_error when an allocation fails rather than unwinding, so it is a process abort rather than an error. Fuzzing the reader found it from two directions, array-tree buffer descriptors and footer segment specs, with exponents from 32 to 61.

What changes are included in this PR?

  • Alignment::MAX_UNTRUSTED (64K) and Alignment::try_from_untrusted_exponent, which rejects anything above it.
  • Use it wherever an exponent comes from a file or message: array-tree buffer descriptors, footer segment specs, postscript segments, and IPC buffer messages. The IPC path used the panicking from_exponent.
  • Regression tests for the array-tree and footer-segment paths, and for the constructor's bounds.

What APIs are changed? Are there any user-facing changes?

Alignment gains a public const and constructor. Reading a file that declares a buffer or segment alignment above 65536 now errors where it previously succeeded. 64K is what some ARM chips use as page alignment, but larger alignments aren't useful here.

I used Claude Code to investigate this and draw up the initial fix and write the tests. The issue itself was found using a libFuzzer-based harness.

## Rationale for this change

Alignments in the file format are a power-of-two exponent in a `u8`, and `try_from_exponent` only
rejects exponents that would overflow a `usize` shift. Satisfying an alignment can require copying
the buffer into an allocation of `len + alignment` bytes, so an exponent of 40 on a 4-byte buffer
asks the reader for 1 TiB.

This cannot be contained by the caller: Rust aborts via `handle_alloc_error` when an allocation
fails rather than unwinding, so it is a process abort rather than an error. Fuzzing the reader finds
it from two directions, array-tree buffer descriptors and footer segment specs, with exponents from
32 to 61.

- Related: vortex-data#8819

## What changes are included in this PR?

- `Alignment::MAX_UNTRUSTED` (4096) and `Alignment::try_from_untrusted_exponent`, which rejects
  anything above it.
- Use it wherever an exponent comes from a file or message: array-tree buffer descriptors, footer
  segment specs, postscript segments, and IPC buffer messages. The IPC path used the panicking
  `from_exponent`.
- Regression tests for the array-tree and footer-segment paths, and for the constructor's bounds.

## What APIs are changed? Are there any user-facing changes?

`Alignment` gains a public const and constructor, both additive. Reading a file that declares a
buffer or segment alignment above 4096 now errors where it previously succeeded. No writer in this
repository records an alignment above `DEFAULT_ALIGNMENT` (256), so this only rejects files a writer
could not have produced without a caller explicitly over-aligning a buffer first.

Signed-off-by: Lorenz Hübschle <[email protected]>
@lorenzhs
lorenzhs requested review from AdamGS and myrrc August 3, 2026 17:44
@codspeed-hq

codspeed-hq Bot commented Aug 3, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 11.17%

❌ 1 regressed benchmark
✅ 1841 untouched benchmarks
⏩ 44 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation decompress[u64, (10000, 256)] 55.3 µs 62.3 µs -11.17%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing lorenzhs:lorenz/bound-serialized-alignment-exponent (d0500b4) with develop (fae9da1)

Open in CodSpeed

Footnotes

  1. 44 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Comment thread vortex-array/src/serde.rs
vortex_bail!("excessive buffer alignment must be rejected");
};
assert!(
err.to_string().contains("exceeds"),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

before the fix, this died with memory allocation of 1099511627780 bytes failed

@lorenzhs lorenzhs added the changelog/fix A bug fix label Aug 4, 2026
Comment thread vortex-buffer/src/alignment.rs Outdated
//github.com/
//github.com/ A copy to satisfy an alignment allocates `len + alignment`, once per buffer, so this bounds
//github.com/ the amplification. 16x the [`Self::DEFAULT_ALIGNMENT`] every writer here records.
pub const MAX_UNTRUSTED: Self = Alignment::new(4096);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we do want to support larger alignments, see #8599

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK sure will bump to 64K

//github.com/
//github.com/ This admits 64KiB page alignment, as used on some ARM systems, while bounding the extra
//github.com/ allocation required to satisfy an alignment from untrusted input.
pub const MAX_UNTRUSTED: Self = Alignment::new(64 * 1024);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@robert3005 are you sure this is enough?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

see the discussion above, as far as I know this is the biggest alignment we ran into so far.

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

Labels

changelog/fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy