VP9RtpDecoder: validate payload bounds (#4703)
Some checks failed
Android / build (push) Has been cancelled
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Docker / build (push) Has been cancelled
Linux / build (push) Has been cancelled
Linux_Python / build (push) Has been cancelled
macOS / build (push) Has been cancelled
macOS_Python / build (push) Has been cancelled
Windows / build (push) Has been cancelled
Windows_Python / build (push) Has been cancelled

This commit is contained in:
Xiaofeng Wang 2026-03-30 10:14:29 +08:00 committed by GitHub
parent 4daa30e229
commit 435dcbcbbf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -109,7 +109,12 @@ struct RTPPayloadVP9 {
#define kVBit 0x02 #define kVBit 0x02
int RTPPayloadVP9::parse(unsigned char *data, int dataLength) { int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
const unsigned char* dataPtr = data; const unsigned char* dataPtr = data;
const unsigned char* dataEnd = data + dataLength;
#define VP9_CHECK_BOUNDS(n) do { if (dataPtr + (n) > dataEnd) return -1; } while (0)
// Parse mandatory first byte of payload descriptor // Parse mandatory first byte of payload descriptor
VP9_CHECK_BOUNDS(1);
this->hasPictureID = (*dataPtr & kIBit); // I bit this->hasPictureID = (*dataPtr & kIBit); // I bit
this->interPicturePrediction = (*dataPtr & kPBit); // P bit this->interPicturePrediction = (*dataPtr & kPBit); // P bit
this->hasLayerIndices = (*dataPtr & kLBit); // L bit this->hasLayerIndices = (*dataPtr & kLBit); // L bit
@ -120,16 +125,19 @@ int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
dataPtr++; dataPtr++;
if (this->hasPictureID) { if (this->hasPictureID) {
VP9_CHECK_BOUNDS(1);
this->largePictureID = (*dataPtr & 0x80); // M bit this->largePictureID = (*dataPtr & 0x80); // M bit
this->pictureID = (*dataPtr & 0x7F); this->pictureID = (*dataPtr & 0x7F);
if (this->largePictureID) { if (this->largePictureID) {
dataPtr++; dataPtr++;
VP9_CHECK_BOUNDS(1);
this->pictureID = ntohs((this->pictureID << 16) + (*dataPtr & 0xFF)); this->pictureID = ntohs((this->pictureID << 16) + (*dataPtr & 0xFF));
} }
dataPtr++; dataPtr++;
} }
if (this->hasLayerIndices) { if (this->hasLayerIndices) {
VP9_CHECK_BOUNDS(1);
this->temporalID = (*dataPtr & 0xE0) >> 5; // T bits this->temporalID = (*dataPtr & 0xE0) >> 5; // T bits
this->isSwitchingUp = (*dataPtr & 0x10); // U bit this->isSwitchingUp = (*dataPtr & 0x10); // U bit
this->spatialID = (*dataPtr & 0x0E) >> 1; // S bits this->spatialID = (*dataPtr & 0x0E) >> 1; // S bits
@ -137,11 +145,13 @@ int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
if (this->flexibleMode) { // marked in webrtc code if (this->flexibleMode) { // marked in webrtc code
do { do {
dataPtr++; dataPtr++;
VP9_CHECK_BOUNDS(1);
this->referenceIdx = (*dataPtr & 0xFE) >> 1; this->referenceIdx = (*dataPtr & 0xFE) >> 1;
this->additionalReferenceIdx = (*dataPtr & 0x01); // D bit this->additionalReferenceIdx = (*dataPtr & 0x01); // D bit
} while (this->additionalReferenceIdx); } while (this->additionalReferenceIdx);
} else { } else {
dataPtr++; dataPtr++;
VP9_CHECK_BOUNDS(1);
this->tl0PicIdx = (*dataPtr & 0xFF); this->tl0PicIdx = (*dataPtr & 0xFF);
} }
dataPtr++; dataPtr++;
@ -151,18 +161,21 @@ int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
/* Skip reference indices */ /* Skip reference indices */
uint8_t nbit; uint8_t nbit;
do { do {
VP9_CHECK_BOUNDS(1);
uint8_t p_diff = (*dataPtr & 0xFE) >> 1; uint8_t p_diff = (*dataPtr & 0xFE) >> 1;
nbit = (*dataPtr & 0x01); nbit = (*dataPtr & 0x01);
dataPtr++; dataPtr++;
} while (nbit); } while (nbit);
} }
if (this->hasScalabilityStructure) { if (this->hasScalabilityStructure) {
VP9_CHECK_BOUNDS(1);
this->spatialLayers = (*dataPtr & 0xE0) >> 5; // N_S bits this->spatialLayers = (*dataPtr & 0xE0) >> 5; // N_S bits
this->hasResolution = (*dataPtr & 0x10); // Y bit this->hasResolution = (*dataPtr & 0x10); // Y bit
this->hasGof = (*dataPtr & 0x08); // G bit this->hasGof = (*dataPtr & 0x08); // G bit
dataPtr++; dataPtr++;
if (this->hasResolution) { if (this->hasResolution) {
for (int i = 0; i <= this->spatialLayers; i++) { for (int i = 0; i <= this->spatialLayers; i++) {
VP9_CHECK_BOUNDS(4);
int width = (dataPtr[0] << 8) + dataPtr[1]; int width = (dataPtr[0] << 8) + dataPtr[1];
dataPtr += 2; dataPtr += 2;
int height = (dataPtr[0] << 8) + dataPtr[1]; int height = (dataPtr[0] << 8) + dataPtr[1];
@ -172,12 +185,15 @@ int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
} }
} }
if (this->hasGof) { if (this->hasGof) {
VP9_CHECK_BOUNDS(1);
this->numberOfFramesInGof = *dataPtr & 0xFF; // N_G bits this->numberOfFramesInGof = *dataPtr & 0xFF; // N_G bits
dataPtr++; dataPtr++;
for (int frame_index = 0; frame_index < this->numberOfFramesInGof; frame_index++) { for (int frame_index = 0; frame_index < this->numberOfFramesInGof; frame_index++) {
// TODO(javierc): Read these values if needed // TODO(javierc): Read these values if needed
VP9_CHECK_BOUNDS(1);
int reference_indices = (*dataPtr & 0x0C) >> 2; // R bits int reference_indices = (*dataPtr & 0x0C) >> 2; // R bits
dataPtr++; dataPtr++;
VP9_CHECK_BOUNDS(reference_indices);
for (int reference_index = 0; reference_index < reference_indices; reference_index++) { for (int reference_index = 0; reference_index < reference_indices; reference_index++) {
dataPtr++; dataPtr++;
} }
@ -185,6 +201,8 @@ int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
} }
} }
#undef VP9_CHECK_BOUNDS
return dataPtr - data; return dataPtr - data;
} }
@ -221,6 +239,10 @@ bool VP9RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
RTPPayloadVP9 info; RTPPayloadVP9 info;
int offset = info.parse(payload, payload_size); int offset = info.parse(payload, payload_size);
if (offset < 0) {
WarnL << "VP9 RTP payload parse failed, seq:" << seq;
return false;
}
// InfoL << rtp->dumpString() << "\n" << info.dump(); // InfoL << rtp->dumpString() << "\n" << info.dump();
bool start = info.beginningOfLayerFrame; bool start = info.beginningOfLayerFrame;
if (start) { if (start) {