Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e27532aa authored by Kim Sungyeon's avatar Kim Sungyeon Committed by Lajos Molnar
Browse files

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: default avatarKim Sungyeon <sy85.kim@samsung.com>
parent 89d5bc68
Loading
Loading
Loading
Loading
+27 −15
Original line number Diff line number Diff line
@@ -112,24 +112,25 @@ int32_t AAVCAssembler::addNack(
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 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit(

    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 @@ void AAVCAssembler::submitAccessUnit() {
    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 @@ inline void AAVCAssembler::printNowTimeUs(int64_t start, int64_t now, int64_t pl
            (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(
+3 −2
Original line number Diff line number Diff line
@@ -63,12 +63,13 @@ private:

    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);
};
+26 −15
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@ int32_t AHEVCAssembler::addNack(
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 @@ ARTPAssembler::AssemblyStatus AHEVCAssembler::addNALUnit(

    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 @@ ARTPAssembler::AssemblyStatus AHEVCAssembler::addNALUnit(

    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 @@ void AHEVCAssembler::submitAccessUnit() {
    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 @@ inline void AHEVCAssembler::printNowTimeUs(int64_t start, int64_t now, int64_t p
            (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);
+4 −3
Original line number Diff line number Diff line
@@ -64,12 +64,13 @@ private:

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