Skip to content

fix(playstation): Add compression limit - #6211

Open
tobias-wilfert wants to merge 6 commits into
masterfrom
tobias-wilfert/fix/playstation-compression-limit
Open

fix(playstation): Add compression limit#6211
tobias-wilfert wants to merge 6 commits into
masterfrom
tobias-wilfert/fix/playstation-compression-limit

Conversation

@tobias-wilfert

@tobias-wilfert tobias-wilfert commented Jul 10, 2026

Copy link
Copy Markdown
Member

Fix: INGEST-994 (More detail in the comments on the ticket).

@tobias-wilfert tobias-wilfert self-assigned this Jul 10, 2026
@linear-code

linear-code Bot commented Jul 10, 2026

Copy link
Copy Markdown

INGEST-994

Comment thread relay-server/src/processing/errors/errors/playstation.rs
}

let decoder = lz4_flex::frame::FrameDecoder::new(Cursor::new(bytes));
let mut decoder = decoder.take(limit.saturating_add(1) as u64);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Mimics the existing logic here:

let decoder = decoder.take(max_size.saturating_add(1) as u64);
)

let data = relay_prosperoconv::extract_data(&prosperodump.payload()).map_err(|err| {
ProcessingError::InvalidPlaystationDump(format!("Failed to extract data: {err}"))
})?;
let data = uncompress(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Did extract_data previously do the compression? If so, wouldn't it make more sense to pass a limit parameter into extract_data, so it can not be abused from (hypothetical) other call sites?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes as pointed out in the above comment the old logic is here. At the time it was written it felt like putting it there made sense, but now I don't really see a point of having it outside of relay. This code here is the only call side so would remove it afterwards.

Comment on lines -648 to -649
# Video size exceeds attachment size limits - we expect this to be ignored
video_content = "1" * (len(playstation_dump) + 2 * 1024 * 1024)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This test was changed a couple month ago without updating the comments and logic here, the video now gets uploaded to objectstore regardless of the max_attachment_size as such update the test to be less misleading.

@tobias-wilfert
tobias-wilfert marked this pull request as ready for review August 4, 2026 09:43
@tobias-wilfert
tobias-wilfert requested a review from a team as a code owner August 4, 2026 09:43

@Dav1dde Dav1dde left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Goal is to then remove it decompression from the prospero crate?

}

#[cfg(all(sentry, feature = "processing"))]
fn uncompress(bytes: Bytes, limit: usize) -> Result<Bytes, CompressionError> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is better suited in utils::playstation.

Comment on lines +69 to 71
ctx.processing.config.max_attachment_size(),
).map_err(ProcessingError::from)?;
let prospero_dump = relay_prosperoconv::ProsperoDump::parse(&data).map_err(|err| {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ProsperoDump::parse has no caller-side depth bound on attacker-controlled data

Attacker-controlled decompressed PlayStation dump data is passed to relay_prosperoconv::ProsperoDump::parse without a visible recursion-depth limit; max_attachment_size bounds memory but not parser depth.

Evidence
  • prosperodump.payload() at line 66 is attacker-controlled input.
  • uncompress() bounds decompressed output to max_attachment_size bytes (line 67), bounding memory but not parsing depth.
  • relay_prosperoconv::ProsperoDump::parse(&data) at line 69 parses the decompressed data without a caller-side depth limit.
  • relay-prosperoconv source is cloned from the tempest repository at build time and is not inspectable here.
  • relay-prosperoconv depends on rmpv, which decodes msgpack recursively; absent a visible max_depth call the parser is vulnerable to stack overflow from a deeply-nested payload.
  • Precedent in this codebase: src/utils/rmp.rs:21 sets max_depth on other msgpack deserializers.

Identified by Warden · wrdn-dos-review · B4G-L2V

Comment on lines +2 to +3
use bytes::Bytes;
#[cfg(all(sentry, feature = "processing"))]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PlayStation decompression bounds memory but not post-decompress CPU

The uncompress function added in this PR caps decompressed memory via .take(limit), yet a tiny LZ4 payload can still inflate to max_attachment_size (default 200 MiB) before relay_prosperoconv::ProsperoDump::parse and write_dump process the full buffer with no caller-side time or depth budget, leaving a CPU-amplification vector on the shared worker.

Evidence
  • relay-server/src/processing/errors/errors/playstation.rs:269 defines uncompress(bytes, limit) which uses lz4_flex::frame::FrameDecoder::new(...).take(limit.saturating_add(1) as u64), bounding only memory.
  • playstation.rs:67 calls uncompress(prosperodump.payload(), ctx.processing.config.max_attachment_size()) where the limit defaults to 200 MiB (relay-config/src/config.rs:726).
  • playstation.rs:71 passes the full decompressed buffer to relay_prosperoconv::ProsperoDump::parse(&data) with no caller-side depth limit, time budget, or item-count cap.
  • playstation.rs:74 then calls relay_prosperoconv::write_dump(&prospero_dump), again with no CPU/time guard.
  • relay-prosperoconv source is cloned from an external git repo at build time (relay-prosperoconv/build.rs), so parser recursion/depth bounds cannot be verified statically; treating it as unbounded per fail-safe review policy.
  • Sibling path relay-server/src/processing/errors/errors/nswitch.rs:23 hardcodes MAX_DECOMPRESSED_SIZE = 100 KiB; the PlayStation path uses the much larger configurable max_attachment_size with no post-decompression CPU guard.
Also found at 1 additional location
  • relay-server/src/processing/errors/errors/playstation.rs:269

Identified by Warden · wrdn-dos-review · X4Q-XCB

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.

3 participants