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
int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
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
VP9_CHECK_BOUNDS(1);
this->hasPictureID = (*dataPtr & kIBit); // I bit
this->interPicturePrediction = (*dataPtr & kPBit); // P bit
this->hasLayerIndices = (*dataPtr & kLBit); // L bit
@ -120,16 +125,19 @@ int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
dataPtr++;
if (this->hasPictureID) {
VP9_CHECK_BOUNDS(1);
this->largePictureID = (*dataPtr & 0x80); // M bit
this->pictureID = (*dataPtr & 0x7F);
if (this->largePictureID) {
dataPtr++;
VP9_CHECK_BOUNDS(1);
this->pictureID = ntohs((this->pictureID << 16) + (*dataPtr & 0xFF));
}
dataPtr++;
}
if (this->hasLayerIndices) {
VP9_CHECK_BOUNDS(1);
this->temporalID = (*dataPtr & 0xE0) >> 5; // T bits
this->isSwitchingUp = (*dataPtr & 0x10); // U bit
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
do {
dataPtr++;
VP9_CHECK_BOUNDS(1);
this->referenceIdx = (*dataPtr & 0xFE) >> 1;
this->additionalReferenceIdx = (*dataPtr & 0x01); // D bit
} while (this->additionalReferenceIdx);
} else {
dataPtr++;
VP9_CHECK_BOUNDS(1);
this->tl0PicIdx = (*dataPtr & 0xFF);
}
dataPtr++;
@ -151,18 +161,21 @@ int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
/* Skip reference indices */
uint8_t nbit;
do {
VP9_CHECK_BOUNDS(1);
uint8_t p_diff = (*dataPtr & 0xFE) >> 1;
nbit = (*dataPtr & 0x01);
dataPtr++;
} while (nbit);
}
if (this->hasScalabilityStructure) {
VP9_CHECK_BOUNDS(1);
this->spatialLayers = (*dataPtr & 0xE0) >> 5; // N_S bits
this->hasResolution = (*dataPtr & 0x10); // Y bit
this->hasGof = (*dataPtr & 0x08); // G bit
dataPtr++;
if (this->hasResolution) {
for (int i = 0; i <= this->spatialLayers; i++) {
VP9_CHECK_BOUNDS(4);
int width = (dataPtr[0] << 8) + dataPtr[1];
dataPtr += 2;
int height = (dataPtr[0] << 8) + dataPtr[1];
@ -172,12 +185,15 @@ int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
}
}
if (this->hasGof) {
VP9_CHECK_BOUNDS(1);
this->numberOfFramesInGof = *dataPtr & 0xFF; // N_G bits
dataPtr++;
for (int frame_index = 0; frame_index < this->numberOfFramesInGof; frame_index++) {
// TODO(javierc): Read these values if needed
VP9_CHECK_BOUNDS(1);
int reference_indices = (*dataPtr & 0x0C) >> 2; // R bits
dataPtr++;
VP9_CHECK_BOUNDS(reference_indices);
for (int reference_index = 0; reference_index < reference_indices; reference_index++) {
dataPtr++;
}
@ -185,6 +201,8 @@ int RTPPayloadVP9::parse(unsigned char *data, int dataLength) {
}
}
#undef VP9_CHECK_BOUNDS
return dataPtr - data;
}
@ -221,6 +239,10 @@ bool VP9RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
RTPPayloadVP9 info;
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();
bool start = info.beginningOfLayerFrame;
if (start) {