mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
C#: fix IndexOutOfRangeException in ReadRawByte on truncated messages (#26914)
**Summary**
A near-int.MaxValue length varint overflows PushLimit, corrupting bufferSize to a negative value. ReadRawByte's == guard then never triggers RefillBuffer, causing an out-of-bounds read instead of InvalidProtocolBufferException.TruncatedMessage().
**Fix**
change == to >= in ReadRawByte. Regression tests added for all four affected slow-path variants.
**Tests**
Added `TruncatedMessageWithLargeInnerLengthThrowsInvalidProtocolBufferException` with 4 test cases.
Fixes #26856
Closes #26914
COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/26914 from pawlos:fix/csharp-readrawbyte-ioob-truncated-message 6bec67cfb2
PiperOrigin-RevId: 914940764
This commit is contained in:
parent
6da2cd928e
commit
fe9848e7b3
2 changed files with 18 additions and 3 deletions
|
|
@ -105,5 +105,18 @@ namespace Google.Protobuf
|
|||
Assert.AreEqual(message, parsed);
|
||||
Assert.AreEqual("test", parsed.None);
|
||||
}
|
||||
|
||||
// Issue 26856: ReadRawByte throws IndexOutOfRangeException instead of
|
||||
// InvalidProtocolBufferException on truncated messages with a near-int.MaxValue
|
||||
// inner length varint, corrupting bufferSize via integer overflow in PushLimit.
|
||||
[Test]
|
||||
[TestCase(new byte[] { 0x2a, 0xff, 0xff, 0xff, 0xff, 0x67, 0x2a, 0xcc }, "ParseRawVarint32SlowPath")]
|
||||
[TestCase(new byte[] { 0x42, 0xfc, 0xff, 0xff, 0xff, 0x57, 0xd8, 0x01 }, "ParseRawVarint64SlowPath")]
|
||||
[TestCase(new byte[] { 0x3a, 0xff, 0xff, 0xff, 0xff, 0x67, 0xb5, 0x34 }, "ParseRawLittleEndian32SlowPath")]
|
||||
[TestCase(new byte[] { 0x42, 0xff, 0xff, 0xff, 0xff, 0x67, 0x39, 0x34 }, "ParseRawLittleEndian64SlowPath")]
|
||||
public void TruncatedMessageWithLargeInnerLengthThrowsInvalidProtocolBufferException(byte[] data, string _)
|
||||
{
|
||||
Assert.Throws<InvalidProtocolBufferException>(() => FileDescriptorProto.Parser.ParseFrom(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,13 +93,15 @@ namespace Google.Protobuf
|
|||
{
|
||||
throw InvalidProtocolBufferException.NegativeSize();
|
||||
}
|
||||
byteLimit += state.totalBytesRetired + state.bufferPos;
|
||||
// Compute in long to avoid int overflow when byteLimit is near int.MaxValue;
|
||||
// the oldLimit guard below ensures the result fits back into int.
|
||||
long absoluteLimit = (long)byteLimit + state.totalBytesRetired + state.bufferPos;
|
||||
int oldLimit = state.currentLimit;
|
||||
if (byteLimit > oldLimit)
|
||||
if (absoluteLimit > oldLimit)
|
||||
{
|
||||
throw InvalidProtocolBufferException.TruncatedMessage();
|
||||
}
|
||||
state.currentLimit = byteLimit;
|
||||
state.currentLimit = (int)absoluteLimit;
|
||||
|
||||
RecomputeBufferSizeAfterLimit(ref state);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue