Pad profile extensions in report MarshalSize - #226
Merged
JoTurk merged 1 commit intoSep 1, 2026
Conversation
RFC 3550 profile-specific extensions are padded out to a whole 32-bit word when a sender or receiver report is marshalled, but neither MarshalSize accounted for that padding. ReceiverReport.MarshalSize left the extensions out entirely, and ReceiverReport.Header added getPadding(len(ProfileExtensions)), a 0-3 byte pad count, to the header length instead of the size of the extensions. Any receiver report carrying extensions was therefore written with a header length that under-reported the packet, and rtcp.Unmarshal rejected its own output. SenderReport.MarshalSize already added the extensions, but not their padding, so it was wrong whenever the extension length was not a multiple of four. Both now add the padded length, ReceiverReport.Header drops the pad term, and ReceiverReport.Marshal copies the extensions into the already-sized buffer the way SenderReport.Marshal does.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #226 +/- ##
==========================================
+ Coverage 77.50% 77.68% +0.17%
==========================================
Files 22 22
Lines 2032 2030 -2
==========================================
+ Hits 1575 1577 +2
+ Misses 359 356 -3
+ Partials 98 97 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
rtcp.Unmarshalrejects aReceiverReportthatReceiverReport.Marshaljust produced, wheneverProfileExtensionsis non-empty:Two mistakes about the padding RFC 3550 requires on profile-specific extensions:
ReceiverReport.MarshalSizeleaves the extensions out altogether — it returns 8 for the packet above — soCompoundPacket.MarshalSize, which sums its members, under-reports too.ReceiverReport.Headercompensates withgetPadding(len(r.ProfileExtensions)), the 0–3 byte pad count rather than the size of the extensions. For a 24-byte extension that term is 0, so the header length stays 1.SenderReportis the in-repo precedent for the right shape: itsMarshalSizeadds the extensions and itsHeaderis the plain(MarshalSize()/4)-1. It adds the unpadded length though, so it is wrong for any extension length that is not a multiple of four.Measured on
b12c5f1,MarshalSize/ bytes written / header length / round trip:Both
MarshalSizemethods now add the padded length,ReceiverReport.Headerdrops the pad term, andReceiverReport.Marshalcopies the extensions into the already-sized buffer the waySenderReport.Marshaldoes.Why nothing caught it: every case in
TestReceiverReportRoundTripsetsProfileExtensions: []byte{}, so the receiver side is never marshalled with extensions at all, and the oneTestSenderReportRoundTripcase that has them uses exactly four bytes.The test went in
packet_test.gosince it covers both types. Reverting both source files fails it on all five extension lengths for the receiver report and on 1 and 5 for the sender report; adding the extensions without the padding still fails 1 and 5 on both; fixing only the receiver report leaves the sender-report cases failing.go test -race ./...green,golangci-lint runclean on v2.10.1 (the version CI pins).Worth flagging: receiver reports with extensions now go out with a different, correct header length. The old output could not be parsed, so I doubt anything relies on it, but it is a wire-format change.
I used Claude Code to help investigate and write this up; the failure came out of fuzzing
MarshalandUnmarshalagainst each other.Reference issue
None — found while fuzzing the marshal/unmarshal round trip.