Truncate CSRC list in RtpPacket::SetCsrcs if too large Truncates the CSRC list to a maximum of 15 entries as per the 4-bit RTP header field limitation, and logs a warning when truncation occurs. Also updates the buffer capacity check and allocation to happen prior to writing data to avoid heap buffer overflow. Additionally, ensure that the underlying buffer size is updated before writing the CSRC data. By calling SetSize prior to WriteAt, we prevent potential heap buffer overflows that could occur if the buffer was not sufficiently allocated before the write operation. Bug: chromium:486317116 Change-Id: I2821867f94c0a8d174fb25047ac1f4b94ee5b867 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/459943 Reviewed-by: Stefan Holmer <stefan@webrtc.org> Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org> Cr-Commit-Position: refs/heads/main@{#47266}
diff --git a/modules/rtp_rtcp/source/rtp_packet.cc b/modules/rtp_rtcp/source/rtp_packet.cc index 97f6b54..2b6cd00 100644 --- a/modules/rtp_rtcp/source/rtp_packet.cc +++ b/modules/rtp_rtcp/source/rtp_packet.cc
@@ -220,16 +220,22 @@ RTC_DCHECK_EQ(extensions_size_, 0); RTC_DCHECK_EQ(payload_size_, 0); RTC_DCHECK_EQ(padding_size_, 0); - RTC_DCHECK_LE(csrcs.size(), 0x0fu); - RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity()); + + if (csrcs.size() > kMaxCsrcs) { + RTC_LOG(LS_ERROR) << "Truncating CSRC list, length exceeded " << kMaxCsrcs + << ": " << csrcs.size(); + csrcs = csrcs.first(kMaxCsrcs); + } + payload_offset_ = kFixedHeaderSize + 4 * csrcs.size(); + buffer_.SetSize(payload_offset_); // SetSize before WriteAt. + WriteAt(0, (data()[0] & 0xF0) | dchecked_cast<uint8_t>(csrcs.size())); size_t offset = kFixedHeaderSize; for (uint32_t csrc : csrcs) { ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc); offset += 4; } - buffer_.SetSize(payload_offset_); } std::span<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
diff --git a/modules/rtp_rtcp/source/rtp_packet.h b/modules/rtp_rtcp/source/rtp_packet.h index 1a9f917..78cccb3 100644 --- a/modules/rtp_rtcp/source/rtp_packet.h +++ b/modules/rtp_rtcp/source/rtp_packet.h
@@ -30,6 +30,12 @@ using ExtensionType = RTPExtensionType; using ExtensionManager = RtpHeaderExtensionMap; + // Maximum number of CSRCs in an RTP packet as specified in section + // "5.1 RTP Fixed Header Fields" of RFC 3550. + // Note: This is a different limit than the one that applies to RTCP packets + // (which is specified in section 6.1). + static constexpr size_t kMaxCsrcs = 15; + // `extensions` required for SetExtension/ReserveExtension functions during // packet creating and used if available in Parse function. // Adding and getting extensions will fail until `extensions` is
diff --git a/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_unittest.cc index 37b5f62..1343d0a 100644 --- a/modules/rtp_rtcp/source/rtp_packet_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -17,6 +17,7 @@ #include <string> #include <type_traits> #include <utility> +#include <vector> #include "absl/strings/string_view.h" #include "api/rtp_headers.h" @@ -1347,5 +1348,27 @@ ElementsAreArray(extension_data)); } +TEST(RtpPacketTest, SetCsrcsTruncatesWhenExceedingMax) { + RtpPacketToSend packet(nullptr); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + + std::vector<uint32_t> many_csrcs; + for (uint32_t i = 0; i < 20; ++i) { + many_csrcs.push_back(kSsrc + i); + } + + // SetCsrcs should truncate to maximum elements allowed. + packet.SetCsrcs(many_csrcs); + + std::vector<uint32_t> csrcs = packet.Csrcs(); + EXPECT_EQ(csrcs.size(), RtpPacket::kMaxCsrcs); + for (size_t i = 0; i < RtpPacket::kMaxCsrcs; ++i) { + EXPECT_EQ(csrcs[i], many_csrcs[i]); + } +} + } // namespace } // namespace webrtc