Merge "Restrict negative and integer overflow timestamps in the WebmFrameThread" into main
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index 9768f97..aaf7465 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -208,6 +208,9 @@
         ALOGE("WriteSampleData() get an NULL buffer.");
         return -EINVAL;
     }
+    if (!mWriter->isSampleMetadataValid(trackIndex, timeUs)) {
+        return -EINVAL;
+    }
     {
         /* As MediaMuxer's writeSampleData handles inputs from multiple tracks,
          * limited the scope of mMuxerLock to this inner block so that the
diff --git a/media/libstagefright/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
index 2b14811..04dcfc0 100644
--- a/media/libstagefright/include/media/stagefright/MediaWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaWriter.h
@@ -54,6 +54,12 @@
         return true;
     }
 
+    // Returns true if the sample data is valid.
+    virtual bool isSampleMetadataValid([[maybe_unused]] size_t trackIndex,
+                                       [[maybe_unused]] int64_t timeUs) {
+        return true;
+    }
+
     virtual status_t addSource(const sp<MediaSource> &source) = 0;
     virtual bool reachedEOS() = 0;
     virtual status_t start(MetaData *params = NULL) = 0;
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index 3823c36..ca862b0 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -67,6 +67,25 @@
     return true;
 }
 
+bool WebmWriter::isSampleMetadataValid(size_t trackIndex, int64_t timeUs) {
+    int64_t prevTimeUs = 0;
+    if (mLastTimestampUsByTrackIndex.find(trackIndex) != mLastTimestampUsByTrackIndex.end()) {
+        prevTimeUs = mLastTimestampUsByTrackIndex[trackIndex];
+    }
+    // WebM has monotonically increasing timestamps
+    if (timeUs < 0 || timeUs < prevTimeUs) {
+        return false;
+    }
+    int64_t lastDurationUs = timeUs - prevTimeUs;
+    // Ensure that the timeUs value does not overflow,
+    // when adding lastDurationUs in the WebmFrameMediaSourceThread.
+    if (timeUs > (INT64_MAX / 1000) - lastDurationUs) {
+        return false;
+    }
+    mLastTimestampUsByTrackIndex[trackIndex] = timeUs;
+    return true;
+}
+
 WebmWriter::WebmWriter(int fd)
     : mFd(dup(fd)),
       mInitCheck(mFd < 0 ? NO_INIT : OK),
diff --git a/media/libstagefright/webm/include/webm/WebmWriter.h b/media/libstagefright/webm/include/webm/WebmWriter.h
index e339add..4c51f0e 100644
--- a/media/libstagefright/webm/include/webm/WebmWriter.h
+++ b/media/libstagefright/webm/include/webm/WebmWriter.h
@@ -40,6 +40,9 @@
     // which is compatible with WebmWriter.
     // Note that this overloads that method in the base class.
     static bool isFdOpenModeValid(int fd);
+    // Returns true if the timestamp is valid which is compatible with the WebmWriter.
+    // Note that this overloads that method in the base class.
+    bool isSampleMetadataValid(size_t trackIndex, int64_t timeUs);
     explicit WebmWriter(int fd);
     ~WebmWriter() { reset(); }
 
@@ -67,6 +70,7 @@
     uint64_t mInfoSize;
     uint64_t mTracksOffset;
     uint64_t mCuesOffset;
+    std::map<size_t, int64_t> mLastTimestampUsByTrackIndex;
 
     bool mPaused;
     bool mStarted;
diff --git a/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp b/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
index fee5c94..7235ba9 100644
--- a/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
+++ b/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
@@ -209,6 +209,9 @@
     }
     vector<FrameData> bufferInfo = mBufferSource->getFrameList(trackIndex);
     for (int idx = startFrameIndex; idx < endFrameIndex; ++idx) {
+        if (!mWriter->isSampleMetadataValid(trackIndex, bufferInfo[idx].timeUs)) {
+            continue;
+        }
         sp<ABuffer> buffer = new ABuffer((void *)bufferInfo[idx].buf, bufferInfo[idx].size);
         MediaBuffer *mediaBuffer = new MediaBuffer(buffer);