Skip to content

Reject trailing bytes in unary Protobuf payloads#4553

Merged
pepone merged 2 commits intoicerpc:mainfrom
pepone:fix/protobuf-unary-trailing-bytes
Apr 27, 2026
Merged

Reject trailing bytes in unary Protobuf payloads#4553
pepone merged 2 commits intoicerpc:mainfrom
pepone:fix/protobuf-unary-trailing-bytes

Conversation

@pepone
Copy link
Copy Markdown
Member

@pepone pepone commented Apr 24, 2026

Summary

  • Unary DecodeProtobufMessageAsync now performs a final read after the single expected message and throws InvalidDataException if trailing bytes remain, so concatenated frames or junk after the message surface as a framing error instead of being silently discarded.
  • Adds tests for a valid message followed by garbage bytes and for two concatenated framed messages.

Fixes #4438

A unary Protobuf payload must contain exactly one length-prefixed
message. DecodeProtobufMessageAsync returned after the first message and
silently let the pipe reader discard any remaining bytes, so concatenated
frames or trailing garbage went unnoticed instead of surfacing as a
framing error.
Copilot AI review requested due to automatic review settings April 24, 2026 11:30
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR tightens unary Protobuf framing by ensuring a unary payload contains exactly one length-prefixed message and fails fast with InvalidDataException when extra bytes follow, addressing audit finding #4438.

Changes:

  • Add a post-decode read in DecodeProtobufMessageAsync to detect and reject any trailing bytes after the single expected message.
  • Add unit tests covering trailing garbage bytes and concatenated framed messages in a unary payload.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/IceRpc.Protobuf/RpcMethods/Internal/PipeReaderExtensions.cs Enforces “exactly one message” semantics for unary Protobuf payload decoding by rejecting trailing bytes.
tests/IceRpc.Protobuf.Tests/PipeReaderExtensionsTests.cs Adds new tests and a helper to construct framed Protobuf payloads with trailing data.

using Google.Protobuf.WellKnownTypes;
using IceRpc.Protobuf.RpcMethods.Internal;
using NUnit.Framework;
using System.Buffers;
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

using System.Buffers; is not used in this test file. The repo has TreatWarningsAsErrors=true, so this unused using will fail the build; please remove it (or use the type that requires it).

Suggested change
using System.Buffers;

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +74
writer.Advance(4);
BinaryPrimitives.WriteInt32BigEndian(lengthBytes, message.CalculateSize());
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

PipeWriter.GetSpan(4) should be written to before calling Advance(4). Advancing first tells the writer these 4 bytes are already initialized, which can violate the PipeWriter contract and makes the test helper brittle.

Suggested change
writer.Advance(4);
BinaryPrimitives.WriteInt32BigEndian(lengthBytes, message.CalculateSize());
BinaryPrimitives.WriteInt32BigEndian(lengthBytes, message.CalculateSize());
writer.Advance(4);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@InsertCreativityHere InsertCreativityHere left a comment

Choose a reason for hiding this comment

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

Looks good to me!

The previous order called Advance(4) on the placeholder span, then
filled it via BinaryPrimitives.WriteInt32BigEndian. The PipeWriter
contract treats Advance as a commit of bytes that have already been
written; the back-patch idiom only applies when the value isn't known
until later. The test helper has the message size up front, so write
the length first and advance once.
@pepone pepone merged commit 80ff266 into icerpc:main Apr 27, 2026
6 of 9 checks passed
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.

[Audit-Medium] single-message Protobuf payloads accept trailing bytes…

4 participants