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