VT: ubsan: Prevent assertion by overflowing rtp-time

[JIRA] NEUS7920-21085, SOC-91604
[Problem] signal 6 (SIGABRT), 'ubsan: add-overflow' happened in addNALUnit()
[Cause] RFC3550 doesn't describe value constrains for rtp-time.
        Although it is 4 bytes value by specification,
        it can be even UINT32_MAX and be zero following by UINT32_MAX.
        This overflow derived assertion while calculate the rtp-time.
[Solution] In H264 & H265 assembler,
           modified all time calculation based on int64_t type.
           Now the assemblers recognize overflowed time values sequencially.
           Some values after the overflow, will be treat as "UINT32_MAX + value"

Bug: 175266635

Change-Id: I4a6854ee2063ae7e409650b28e1a9153c441d08d
Signed-off-by: Kim Sungyeon <sy85.kim@samsung.com>
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index 72a377d..2f93d5d 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -112,24 +112,25 @@
 ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit(
         const sp<ARTPSource> &source) {
     List<sp<ABuffer> > *queue = source->queue();
+    const uint32_t firstRTPTime = source->mFirstRtpTime;
 
     if (queue->empty()) {
         return NOT_ENOUGH_DATA;
     }
 
     sp<ABuffer> buffer = *queue->begin();
-    uint32_t rtpTime;
-    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
     buffer->meta()->setObject("source", source);
 
+    int64_t rtpTime = findRTPTime(firstRTPTime, buffer);
+
     int64_t startTime = source->mFirstSysTime / 1000;
     int64_t nowTime = ALooper::GetNowUs() / 1000;
     int64_t playedTime = nowTime - startTime;
-    int64_t playedTimeRtp =
-        source->mFirstRtpTime + (((uint32_t)playedTime) * (source->mClockRate / 1000));
-    const uint32_t jitterTime =
-        (uint32_t)(source->mClockRate / ((float)1000 / (source->mJbTimeMs)));
-    uint32_t expiredTimeInJb = rtpTime + jitterTime;
+
+    int64_t playedTimeRtp = source->mFirstRtpTime + playedTime * (int64_t)source->mClockRate / 1000;
+    const int64_t jitterTime = source->mJbTimeMs * (int64_t)source->mClockRate / 1000;
+
+    int64_t expiredTimeInJb = rtpTime + jitterTime;
     bool isExpired = expiredTimeInJb <= (playedTimeRtp);
     bool isTooLate200 = expiredTimeInJb < (playedTimeRtp - jitterTime);
     bool isTooLate300 = expiredTimeInJb < (playedTimeRtp - (jitterTime * 3 / 2));
@@ -154,11 +155,11 @@
 
     if (isTooLate300) {
         ALOGW("buffer arrived after 300ms ... \t Diff in Jb=%lld \t Seq# %d",
-              ((long long)playedTimeRtp) - expiredTimeInJb, buffer->int32Data());
+                (long long)(playedTimeRtp - expiredTimeInJb), buffer->int32Data());
         printNowTimeUs(startTime, nowTime, playedTime);
         printRTPTime(rtpTime, playedTimeRtp, expiredTimeInJb, isExpired);
 
-        mNextExpectedSeqNo = pickProperSeq(queue, jitterTime, playedTimeRtp);
+        mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTime);
     }
 
     if (mNextExpectedSeqNoValid) {
@@ -564,14 +565,25 @@
     msg->post();
 }
 
-int32_t AAVCAssembler::pickProperSeq(const Queue *queue, uint32_t jit, int64_t play) {
+inline int64_t AAVCAssembler::findRTPTime(
+        const uint32_t& firstRTPTime, const sp<ABuffer>& buffer) {
+    /* If you want to +, -, * rtpTime, recommend to declare rtpTime as int64_t.
+       Because rtpTime can be near UINT32_MAX. Beware the overflow. */
+    int64_t rtpTime = 0;
+    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    // If the first overs 2^31 and rtp unders 2^31, the rtp value is overflowed one.
+    int64_t overflowMask = (firstRTPTime & 0x80000000 & ~rtpTime) << 1;
+    return rtpTime | overflowMask;
+}
+
+int32_t AAVCAssembler::pickProperSeq(const Queue *queue,
+        uint32_t first, int64_t play, int64_t jit) {
     sp<ABuffer> buffer = *(queue->begin());
-    uint32_t rtpTime;
     int32_t nextSeqNo = buffer->int32Data();
 
     Queue::const_iterator it = queue->begin();
     while (it != queue->end()) {
-        CHECK((*it)->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+        int64_t rtpTime = findRTPTime(first, *it);
         // if pkt in time exists, that should be the next pivot
         if (rtpTime + jit >= play) {
             nextSeqNo = (*it)->int32Data();
@@ -613,9 +625,9 @@
             (long long)start, (long long)now, (long long)play);
 }
 
-inline void AAVCAssembler::printRTPTime(uint32_t rtp, int64_t play, uint32_t exp, bool isExp) {
-    ALOGD("rtp-time(JB)=%u, played-rtp-time(JB)=%lld, expired-rtp-time(JB)=%u isExpired=%d",
-            rtp, (long long)play, exp, isExp);
+inline void AAVCAssembler::printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp) {
+    ALOGD("rtp-time(JB)=%lld, played-rtp-time(JB)=%lld, expired-rtp-time(JB)=%lld expired=%d",
+            (long long)rtp, (long long)play, (long long)exp, isExp);
 }
 
 ARTPAssembler::AssemblyStatus AAVCAssembler::assembleMore(
diff --git a/media/libstagefright/rtsp/AAVCAssembler.h b/media/libstagefright/rtsp/AAVCAssembler.h
index 79fc7c2..9d71e2f 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.h
+++ b/media/libstagefright/rtsp/AAVCAssembler.h
@@ -63,12 +63,13 @@
 
     void submitAccessUnit();
 
-    int32_t pickProperSeq(const Queue *q, uint32_t jit, int64_t play);
+    inline int64_t findRTPTime(const uint32_t& firstRTPTime, const sp<ABuffer>& buffer);
+    int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
     bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
             size_t avail, float goodRatio);
     int32_t deleteUnitUnderSeq(Queue *q, uint32_t seq);
     void printNowTimeUs(int64_t start, int64_t now, int64_t play);
-    void printRTPTime(uint32_t rtp, int64_t play, uint32_t exp, bool isExp);
+    void printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp);
 
     DISALLOW_EVIL_CONSTRUCTORS(AAVCAssembler);
 };
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.cpp b/media/libstagefright/rtsp/AHEVCAssembler.cpp
index 148a0ba..553ea08 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AHEVCAssembler.cpp
@@ -122,6 +122,7 @@
 ARTPAssembler::AssemblyStatus AHEVCAssembler::addNALUnit(
         const sp<ARTPSource> &source) {
     List<sp<ABuffer> > *queue = source->queue();
+    const uint32_t firstRTPTime = source->mFirstRtpTime;
 
     if (queue->empty()) {
         return NOT_ENOUGH_DATA;
@@ -129,15 +130,15 @@
 
     sp<ABuffer> buffer = *queue->begin();
     buffer->meta()->setObject("source", source);
-    uint32_t rtpTime;
-    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    int64_t rtpTime = findRTPTime(firstRTPTime, buffer);
+
     int64_t startTime = source->mFirstSysTime / 1000;
     int64_t nowTime = ALooper::GetNowUs() / 1000;
     int64_t playedTime = nowTime - startTime;
-    int64_t playedTimeRtp = source->mFirstRtpTime +
-        (((uint32_t)playedTime) * (source->mClockRate / 1000));
-    const uint32_t jitterTime = (uint32_t)(source->mClockRate / ((float)1000 / (source->mJbTimeMs)));
-    uint32_t expiredTimeInJb = rtpTime + jitterTime;
+    int64_t playedTimeRtp = source->mFirstRtpTime + playedTime * (int64_t)source->mClockRate / 1000;
+    const int64_t jitterTime = source->mJbTimeMs * (int64_t)source->mClockRate / 1000;
+
+    int64_t expiredTimeInJb = rtpTime + jitterTime;
     bool isExpired = expiredTimeInJb <= (playedTimeRtp);
     bool isTooLate200 = expiredTimeInJb < (playedTimeRtp - jitterTime);
     bool isTooLate300 = expiredTimeInJb < (playedTimeRtp - (jitterTime * 3 / 2));
@@ -162,11 +163,11 @@
 
     if (isTooLate300) {
         ALOGW("buffer arrived after 300ms ... \t Diff in Jb=%lld \t Seq# %d",
-              ((long long)playedTimeRtp) - expiredTimeInJb, buffer->int32Data());
+                (long long)(playedTimeRtp - expiredTimeInJb), buffer->int32Data());
         printNowTimeUs(startTime, nowTime, playedTime);
         printRTPTime(rtpTime, playedTimeRtp, expiredTimeInJb, isExpired);
 
-        mNextExpectedSeqNo = pickProperSeq(queue, jitterTime, playedTimeRtp);
+        mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTime);
     }
 
     if (mNextExpectedSeqNoValid) {
@@ -577,14 +578,25 @@
     msg->post();
 }
 
-int32_t AHEVCAssembler::pickProperSeq(const Queue *queue, uint32_t jit, int64_t play) {
+inline int64_t AHEVCAssembler::findRTPTime(
+        const uint32_t& firstRTPTime, const sp<ABuffer>& buffer) {
+    /* If you want to +, -, * rtpTime, recommend to declare rtpTime as int64_t.
+       Because rtpTime can be near UINT32_MAX. Beware the overflow. */
+    int64_t rtpTime = 0;
+    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    // If the first overs 2^31 and rtp unders 2^31, the rtp value is overflowed one.
+    int64_t overflowMask = (firstRTPTime & 0x80000000 & ~rtpTime) << 1;
+    return rtpTime | overflowMask;
+}
+
+int32_t AHEVCAssembler::pickProperSeq(const Queue *queue,
+        uint32_t first, int64_t play, int64_t jit) {
     sp<ABuffer> buffer = *(queue->begin());
-    uint32_t rtpTime;
     int32_t nextSeqNo = buffer->int32Data();
 
     Queue::const_iterator it = queue->begin();
     while (it != queue->end()) {
-        CHECK((*it)->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+        int64_t rtpTime = findRTPTime(first, *it);
         // if pkt in time exists, that should be the next pivot
         if (rtpTime + jit >= play) {
             nextSeqNo = (*it)->int32Data();
@@ -626,12 +638,11 @@
             (long long)start, (long long)now, (long long)play);
 }
 
-inline void AHEVCAssembler::printRTPTime(uint32_t rtp, int64_t play, uint32_t exp, bool isExp) {
-    ALOGD("rtp-time(JB)=%u, played-rtp-time(JB)=%lld, expired-rtp-time(JB)=%u isExpired=%d",
-            rtp, (long long)play, exp, isExp);
+inline void AHEVCAssembler::printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp) {
+    ALOGD("rtp-time(JB)=%lld, played-rtp-time(JB)=%lld, expired-rtp-time(JB)=%lld expired=%d",
+            (long long)rtp, (long long)play, (long long)exp, isExp);
 }
 
-
 ARTPAssembler::AssemblyStatus AHEVCAssembler::assembleMore(
         const sp<ARTPSource> &source) {
     AssemblyStatus status = addNALUnit(source);
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.h b/media/libstagefright/rtsp/AHEVCAssembler.h
index 16fc1c8..bf1cded 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.h
+++ b/media/libstagefright/rtsp/AHEVCAssembler.h
@@ -64,12 +64,13 @@
 
     void submitAccessUnit();
 
-    int32_t pickProperSeq(const Queue *queue, uint32_t jit, int64_t play);
-    bool recycleUnit(uint32_t start, uint32_t end, uint32_t conneceted,
+    inline int64_t findRTPTime(const uint32_t& firstRTPTime, const sp<ABuffer>& buffer);
+    int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
+    bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
              size_t avail, float goodRatio);
     int32_t deleteUnitUnderSeq(Queue *queue, uint32_t seq);
     void printNowTimeUs(int64_t start, int64_t now, int64_t play);
-    void printRTPTime(uint32_t rtp, int64_t play, uint32_t exp, bool isExp);
+    void printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp);
 
     DISALLOW_EVIL_CONSTRUCTORS(AHEVCAssembler);
 };