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);
};