PRBool nsSkeletonState::DecodeIndex(ogg_packet* aPacket) { NS_ASSERTION(aPacket->bytes >= SKELETON_4_0_MIN_INDEX_LEN, "Index must be at least minimum size"); if (!mActive) { return PR_FALSE; } PRUint32 serialno = LEUint32(aPacket->packet + INDEX_SERIALNO_OFFSET); PRInt64 numKeyPoints = LEInt64(aPacket->packet + INDEX_NUM_KEYPOINTS_OFFSET); PRInt64 n = 0; PRInt64 endTime = 0, startTime = 0; const unsigned char* p = aPacket->packet; PRInt64 timeDenom = LEInt64(aPacket->packet + INDEX_TIME_DENOM_OFFSET); if (timeDenom == 0) { LOG(PR_LOG_DEBUG, ("Ogg Skeleton Index packet for stream %u has 0 " "timestamp denominator.", serialno)); return (mActive = PR_FALSE); } // Extract the start time. n = LEInt64(p + INDEX_FIRST_NUMER_OFFSET); PRInt64 t; if (!MulOverflow(n, 1000, t)) { return (mActive = PR_FALSE); } else { startTime = t / timeDenom; } // Extract the end time. n = LEInt64(p + INDEX_LAST_NUMER_OFFSET); if (!MulOverflow(n, 1000, t)) { return (mActive = PR_FALSE); } else { endTime = t / timeDenom; } // Check the numKeyPoints value read, ensure we're not going to run out of // memory while trying to decode the index packet. PRInt64 minPacketSize; if (!MulOverflow(numKeyPoints, MIN_KEY_POINT_SIZE, minPacketSize) || !AddOverflow(INDEX_KEYPOINT_OFFSET, minPacketSize, minPacketSize)) { return (mActive = PR_FALSE); } PRInt64 sizeofIndex = aPacket->bytes - INDEX_KEYPOINT_OFFSET; PRInt64 maxNumKeyPoints = sizeofIndex / MIN_KEY_POINT_SIZE; if (aPacket->bytes < minPacketSize || numKeyPoints > maxNumKeyPoints || numKeyPoints < 0) { // Packet size is less than the theoretical minimum size, or the packet is // claiming to store more keypoints than it's capable of storing. This means // that the numKeyPoints field is too large or small for the packet to // possibly contain as many packets as it claims to, so the numKeyPoints // field is possibly malicious. Don't try decoding this index, we may run // out of memory. LOG(PR_LOG_DEBUG, ("Possibly malicious number of key points reported " "(%lld) in index packet for stream %u.", numKeyPoints, serialno)); return (mActive = PR_FALSE); } nsAutoPtr<nsKeyFrameIndex> keyPoints(new nsKeyFrameIndex(startTime, endTime)); p = aPacket->packet + INDEX_KEYPOINT_OFFSET; const unsigned char* limit = aPacket->packet + aPacket->bytes; PRInt64 numKeyPointsRead = 0; PRInt64 offset = 0; PRInt64 time = 0; while (p < limit && numKeyPointsRead < numKeyPoints) { PRInt64 delta = 0; p = ReadVariableLengthInt(p, limit, delta); if (p == limit || !AddOverflow(offset, delta, offset) || offset > mLength || offset < 0) { return (mActive = PR_FALSE); } p = ReadVariableLengthInt(p, limit, delta); if (!AddOverflow(time, delta, time) || time > endTime || time < startTime) { return (mActive = PR_FALSE); } PRInt64 timeMs = 0; if (!MulOverflow(time, 1000, timeMs)) return mActive = PR_FALSE; timeMs /= timeDenom; keyPoints->Add(offset, timeMs); numKeyPointsRead++; } PRInt32 keyPointsRead = keyPoints->Length(); if (keyPointsRead > 0) { mIndex.Put(serialno, keyPoints.forget()); } LOG(PR_LOG_DEBUG, ("Loaded %d keypoints for Skeleton on stream %u", keyPointsRead, serialno)); return PR_TRUE; }
bool SkeletonState::DecodeIndex(ogg_packet* aPacket) { NS_ASSERTION(aPacket->bytes >= SKELETON_4_0_MIN_INDEX_LEN, "Index must be at least minimum size"); if (!mActive) { return false; } uint32_t serialno = LittleEndian::readUint32(aPacket->packet + INDEX_SERIALNO_OFFSET); int64_t numKeyPoints = LittleEndian::readInt64(aPacket->packet + INDEX_NUM_KEYPOINTS_OFFSET); int64_t endTime = 0, startTime = 0; const unsigned char* p = aPacket->packet; int64_t timeDenom = LittleEndian::readInt64(aPacket->packet + INDEX_TIME_DENOM_OFFSET); if (timeDenom == 0) { LOG(PR_LOG_DEBUG, ("Ogg Skeleton Index packet for stream %u has 0 " "timestamp denominator.", serialno)); return (mActive = false); } // Extract the start time. CheckedInt64 t = CheckedInt64(LittleEndian::readInt64(p + INDEX_FIRST_NUMER_OFFSET)) * USECS_PER_S; if (!t.isValid()) { return (mActive = false); } else { startTime = t.value() / timeDenom; } // Extract the end time. t = LittleEndian::readInt64(p + INDEX_LAST_NUMER_OFFSET) * USECS_PER_S; if (!t.isValid()) { return (mActive = false); } else { endTime = t.value() / timeDenom; } // Check the numKeyPoints value read, ensure we're not going to run out of // memory while trying to decode the index packet. CheckedInt64 minPacketSize = (CheckedInt64(numKeyPoints) * MIN_KEY_POINT_SIZE) + INDEX_KEYPOINT_OFFSET; if (!minPacketSize.isValid()) { return (mActive = false); } int64_t sizeofIndex = aPacket->bytes - INDEX_KEYPOINT_OFFSET; int64_t maxNumKeyPoints = sizeofIndex / MIN_KEY_POINT_SIZE; if (aPacket->bytes < minPacketSize.value() || numKeyPoints > maxNumKeyPoints || numKeyPoints < 0) { // Packet size is less than the theoretical minimum size, or the packet is // claiming to store more keypoints than it's capable of storing. This means // that the numKeyPoints field is too large or small for the packet to // possibly contain as many packets as it claims to, so the numKeyPoints // field is possibly malicious. Don't try decoding this index, we may run // out of memory. LOG(PR_LOG_DEBUG, ("Possibly malicious number of key points reported " "(%lld) in index packet for stream %u.", numKeyPoints, serialno)); return (mActive = false); } nsAutoPtr<nsKeyFrameIndex> keyPoints(new nsKeyFrameIndex(startTime, endTime)); p = aPacket->packet + INDEX_KEYPOINT_OFFSET; const unsigned char* limit = aPacket->packet + aPacket->bytes; int64_t numKeyPointsRead = 0; CheckedInt64 offset = 0; CheckedInt64 time = 0; while (p < limit && numKeyPointsRead < numKeyPoints) { int64_t delta = 0; p = ReadVariableLengthInt(p, limit, delta); offset += delta; if (p == limit || !offset.isValid() || offset.value() > mLength || offset.value() < 0) { return (mActive = false); } p = ReadVariableLengthInt(p, limit, delta); time += delta; if (!time.isValid() || time.value() > endTime || time.value() < startTime) { return (mActive = false); } CheckedInt64 timeUsecs = time * USECS_PER_S; if (!timeUsecs.isValid()) return mActive = false; timeUsecs /= timeDenom; keyPoints->Add(offset.value(), timeUsecs.value()); numKeyPointsRead++; } int32_t keyPointsRead = keyPoints->Length(); if (keyPointsRead > 0) { mIndex.Put(serialno, keyPoints.forget()); } LOG(PR_LOG_DEBUG, ("Loaded %d keypoints for Skeleton on stream %u", keyPointsRead, serialno)); return true; }