SkCodec* SkIcoCodec::NewFromStream(SkStream* stream, Result* result) {
    std::unique_ptr<SkStream> inputStream(stream);

 static const uint32_t kIcoDirectoryBytes = 6;
 static const uint32_t kIcoDirEntryBytes = 16;

    std::unique_ptr<uint8_t[]> dirBuffer(new uint8_t[kIcoDirectoryBytes]);
 if (inputStream.get()->read(dirBuffer.get(), kIcoDirectoryBytes) !=
            kIcoDirectoryBytes) {
 SkCodecPrintf("Error: unable to read ico directory header.\n");
 *result = kIncompleteInput;
 return nullptr;
 }

 const uint16_t numImages = get_short(dirBuffer.get(), 4);
 if (0 == numImages) {
 SkCodecPrintf("Error: No images embedded in ico.\n");
 *result = kInvalidInput;
 return nullptr;
 }

 struct Entry {

         uint32_t offset;
         uint32_t size;
     };
    SkAutoFree dirEntryBuffer(sk_malloc_canfail(sizeof(Entry) * numImages));
     if (!dirEntryBuffer) {
         SkCodecPrintf("Error: OOM allocating ICO directory for %i images.\n",
                       numImages);
 *result = kInternalError;
 return nullptr;
 }
 auto* directoryEntries = reinterpret_cast<Entry*>(dirEntryBuffer.get());

 for (uint32_t i = 0; i < numImages; i++) {
 uint8_t entryBuffer[kIcoDirEntryBytes];
 if (inputStream->read(entryBuffer, kIcoDirEntryBytes) !=
                kIcoDirEntryBytes) {
 SkCodecPrintf("Error: Dir entries truncated in ico.\n");
 *result = kIncompleteInput;
 return nullptr;
 }

 uint32_t size = get_int(entryBuffer, 8);

 uint32_t offset = get_int(entryBuffer, 12);

        directoryEntries[i].offset = offset;
        directoryEntries[i].size = size;
 }

 *result = kInvalidInput;

 struct EntryLessThan {
 bool operator() (Entry a, Entry b) const {
 return a.offset < b.offset;
 }
 };
 EntryLessThan lessThan;
 SkTQSort(directoryEntries, &directoryEntries[numImages - 1], lessThan);

 uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes;
    std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> codecs(
 new (SkTArray<std::unique_ptr<SkCodec>, true>)(numImages));
 for (uint32_t i = 0; i < numImages; i++) {
 uint32_t offset = directoryEntries[i].offset;
 uint32_t size = directoryEntries[i].size;

 if (offset < bytesRead) {
 SkCodecPrintf("Warning: invalid ico offset.\n");
 continue;
 }

 if (inputStream.get()->skip(offset - bytesRead) != offset - bytesRead) {
 SkCodecPrintf("Warning: could not skip to ico offset.\n");
 break;
 }

         bytesRead = offset;

        SkAutoFree buffer(sk_malloc_canfail(size));
         if (!buffer) {
             SkCodecPrintf("Warning: OOM trying to create embedded stream.\n");
             break;
 }

 if (inputStream->read(buffer.get(), size) != size) {
 SkCodecPrintf("Warning: could not create embedded stream.\n");
 *result = kIncompleteInput;
 break;
 }

        sk_sp<SkData> data(SkData::MakeFromMalloc(buffer.release(), size));
        std::unique_ptr<SkMemoryStream> embeddedStream(new SkMemoryStream(data));
        bytesRead += size;

 SkCodec* codec = nullptr;
 Result dummyResult;
 if (SkPngCodec::IsPng((const char*) data->bytes(), data->size())) {
            codec = SkPngCodec::NewFromStream(embeddedStream.release(), &dummyResult);
 } else {
            codec = SkBmpCodec::NewFromIco(embeddedStream.release(), &dummyResult);
 }

 if (nullptr != codec) {
            codecs->push_back().reset(codec);
 }
 }

 if (0 == codecs->count()) {
 SkCodecPrintf("Error: could not find any valid embedded ico codecs.\n");
 return nullptr;
 }

 size_t maxSize = 0;
 int maxIndex = 0;
 for (int i = 0; i < codecs->count(); i++) {
 SkImageInfo info = codecs->operator[](i)->getInfo();
 size_t size = info.getSafeSize(info.minRowBytes());

 if (size > maxSize) {
            maxSize = size;
            maxIndex = i;
 }
 }
 int width = codecs->operator[](maxIndex)->getInfo().width();
 int height = codecs->operator[](maxIndex)->getInfo().height();
 SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo();
 SkColorSpace* colorSpace = codecs->operator[](maxIndex)->getInfo().colorSpace();

 *result = kSuccess;
 return new SkIcoCodec(width, height, info, codecs.release(), sk_ref_sp(colorSpace));
}


AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
 int numsubsamples,
 uint8_t key[16],
 uint8_t iv[16],
 cryptoinfo_mode_t mode,
 size_t *clearbytes,

         size_t *encryptedbytes) {

    size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
     AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
     if (!ret) {
         ALOGE("couldn't allocate %zu bytes", cryptosize);
 return NULL;
 }
    ret->numsubsamples = numsubsamples;
    memcpy(ret->key, key, 16);
    memcpy(ret->iv, iv, 16);
    ret->mode = mode;
    ret->pattern.encryptBlocks = 0;
    ret->pattern.skipBlocks = 0;

    ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
    ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes

    memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
    memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));

 return ret;
}

In AMediaCodecCryptoInfo_new of NdkMediaCodec.cpp, there is a possible out-of-bounds write due to an integer overflow. This could lead to remote code execution in external apps with no additional execution privileges needed. User interaction is needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android-9.0 Android ID: A-111603051


AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
 int numsubsamples,
 uint8_t key[16],
 uint8_t iv[16],
 cryptoinfo_mode_t mode,
 size_t *clearbytes,

         size_t *encryptedbytes) {

    size_t cryptosize;
    // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
    if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
            __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
        ALOGE("crypto size overflow");
        return NULL;
    }
     AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
     if (!ret) {
         ALOGE("couldn't allocate %zu bytes", cryptosize);
 return NULL;
 }
    ret->numsubsamples = numsubsamples;
    memcpy(ret->key, key, 16);
    memcpy(ret->iv, iv, 16);
    ret->mode = mode;
    ret->pattern.encryptBlocks = 0;
    ret->pattern.skipBlocks = 0;

    ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
    ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes

    memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
    memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));

 return ret;
}


 static Maybe<bool> CollectValuesOrEntriesImpl(

       Isolate* isolate, Handle<JSObject> object,
       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
       PropertyFilter filter) {
    int count = 0;
     KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
                                ALL_PROPERTIES);
     Subclass::CollectElementIndicesImpl(
         object, handle(object->elements(), isolate), &accumulator);
     Handle<FixedArray> keys = accumulator.GetKeys();

    for (int i = 0; i < keys->length(); ++i) {
       Handle<Object> key(keys->get(i), isolate);
      Handle<Object> value;
       uint32_t index;
       if (!key->ToUint32(&index)) continue;

       uint32_t entry = Subclass::GetEntryForIndexImpl(
           isolate, *object, object->elements(), index, filter);
       if (entry == kMaxUInt32) continue;

       PropertyDetails details = Subclass::GetDetailsImpl(*object, entry);

       if (details.kind() == kData) {
         value = Subclass::GetImpl(isolate, object->elements(), entry);
       } else {
         LookupIterator it(isolate, object, index, LookupIterator::OWN);
         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
             isolate, value, Object::GetProperty(&it), Nothing<bool>());
       }
      if (get_entries) {
        value = MakeEntryPair(isolate, index, value);
       }
       values_or_entries->set(count++, *value);
     }

 *nof_items = count;
 return Just(true);
 }

In CollectValuesOrEntriesImpl of elements.cc, there is possible remote code execution due to type confusion. This could lead to remote escalation of privilege with no additional execution privileges needed. User interaction is needed for exploitation. Product: Android. Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android-9.0 Android ID: A-111274046


 static Maybe<bool> CollectValuesOrEntriesImpl(

       Isolate* isolate, Handle<JSObject> object,
       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
       PropertyFilter filter) {
    DCHECK_EQ(*nof_items, 0);
     KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
                                ALL_PROPERTIES);
     Subclass::CollectElementIndicesImpl(
         object, handle(object->elements(), isolate), &accumulator);
     Handle<FixedArray> keys = accumulator.GetKeys();

    int count = 0;
    int i = 0;
    Handle<Map> original_map(object->map(), isolate);

    for (; i < keys->length(); ++i) {
       Handle<Object> key(keys->get(i), isolate);
       uint32_t index;
       if (!key->ToUint32(&index)) continue;

      DCHECK_EQ(object->map(), *original_map);
       uint32_t entry = Subclass::GetEntryForIndexImpl(
           isolate, *object, object->elements(), index, filter);
       if (entry == kMaxUInt32) continue;

       PropertyDetails details = Subclass::GetDetailsImpl(*object, entry);

      Handle<Object> value;
       if (details.kind() == kData) {
         value = Subclass::GetImpl(isolate, object->elements(), entry);
       } else {
        // This might modify the elements and/or change the elements kind.
         LookupIterator it(isolate, object, index, LookupIterator::OWN);
         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
             isolate, value, Object::GetProperty(&it), Nothing<bool>());
       }
      if (get_entries) value = MakeEntryPair(isolate, index, value);
      values_or_entries->set(count++, *value);
      if (object->map() != *original_map) break;
    }

    // Slow path caused by changes in elements kind during iteration.
    for (; i < keys->length(); i++) {
      Handle<Object> key(keys->get(i), isolate);
      uint32_t index;
      if (!key->ToUint32(&index)) continue;

      if (filter & ONLY_ENUMERABLE) {
        InternalElementsAccessor* accessor =
            reinterpret_cast<InternalElementsAccessor*>(
                object->GetElementsAccessor());
        uint32_t entry = accessor->GetEntryForIndex(isolate, *object,
                                                    object->elements(), index);
        if (entry == kMaxUInt32) continue;
        PropertyDetails details = accessor->GetDetails(*object, entry);
        if (!details.IsEnumerable()) continue;
       }

      Handle<Object> value;
      LookupIterator it(isolate, object, index, LookupIterator::OWN);
      ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::GetProperty(&it),
                                       Nothing<bool>());

      if (get_entries) value = MakeEntryPair(isolate, index, value);
       values_or_entries->set(count++, *value);
     }

 *nof_items = count;
 return Just(true);
 }


void ihevcd_parse_sei_payload(codec_t *ps_codec,
                              UWORD32 u4_payload_type,
                              UWORD32 u4_payload_size,
                              WORD8 i1_nal_type)
{
 parse_ctxt_t *ps_parse = &ps_codec->s_parse;
 bitstrm_t *ps_bitstrm = &ps_parse->s_bitstrm;
    WORD32 payload_bits_remaining = 0;
 sps_t *ps_sps;

    UWORD32 i;

 for(i = 0; i < MAX_SPS_CNT; i++)
 {
        ps_sps = ps_codec->ps_sps_base + i;
 if(ps_sps->i1_sps_valid)
 {
 break;
 }
 }
 if(NULL == ps_sps)
 {
 return;
 }

 if(NAL_PREFIX_SEI == i1_nal_type)
 {
 switch(u4_payload_type)
 {
 case SEI_BUFFERING_PERIOD:
                ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                ihevcd_parse_buffering_period_sei(ps_codec, ps_sps);
 break;

 case SEI_PICTURE_TIMING:
                ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                ihevcd_parse_pic_timing_sei(ps_codec, ps_sps);
 break;

 case SEI_TIME_CODE:
                ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                ihevcd_parse_time_code_sei(ps_codec);
 break;

 case SEI_MASTERING_DISPLAY_COLOUR_VOLUME:
                ps_parse->s_sei_params.i4_sei_mastering_disp_colour_vol_params_present_flags = 1;
                ihevcd_parse_mastering_disp_params_sei(ps_codec);
 break;

             case SEI_USER_DATA_REGISTERED_ITU_T_T35:
                 ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                ihevcd_parse_user_data_registered_itu_t_t35(ps_codec,
                                                            u4_payload_size);
                 break;

             default:
 for(i = 0; i < u4_payload_size; i++)
 {
                    ihevcd_bits_flush(ps_bitstrm, 8);
 }
 break;
 }
 }
 else /* NAL_SUFFIX_SEI */
 {
 switch(u4_payload_type)

         {
             case SEI_USER_DATA_REGISTERED_ITU_T_T35:
                 ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                ihevcd_parse_user_data_registered_itu_t_t35(ps_codec,
                                                            u4_payload_size);
                 break;

             default:
 for(i = 0; i < u4_payload_size; i++)
 {
                    ihevcd_bits_flush(ps_bitstrm, 8);
 }
 break;
 }
 }

 /**
     * By definition the underlying bitstream terminates in a byte-aligned manner.
     * 1. Extract all bar the last MIN(bitsremaining,nine) bits as reserved_payload_extension_data
     * 2. Examine the final 8 bits to determine the payload_bit_equal_to_one marker
     * 3. Extract the remainingreserved_payload_extension_data bits.
     *
     * If there are fewer than 9 bits available, extract them.
     */

    payload_bits_remaining = ihevcd_bits_num_bits_remaining(ps_bitstrm);
 if(payload_bits_remaining) /* more_data_in_payload() */
 {
        WORD32 final_bits;
        WORD32 final_payload_bits = 0;
        WORD32 mask = 0xFF;
        UWORD32 u4_dummy;
        UWORD32 u4_reserved_payload_extension_data;
        UNUSED(u4_dummy);
        UNUSED(u4_reserved_payload_extension_data);

 while(payload_bits_remaining > 9)
 {
            BITS_PARSE("reserved_payload_extension_data",
                       u4_reserved_payload_extension_data, ps_bitstrm, 1);
            payload_bits_remaining--;
 }

        final_bits = ihevcd_bits_nxt(ps_bitstrm, payload_bits_remaining);

 while(final_bits & (mask >> final_payload_bits))
 {
            final_payload_bits++;
 continue;
 }

 while(payload_bits_remaining > (9 - final_payload_bits))
 {
            BITS_PARSE("reserved_payload_extension_data",
                       u4_reserved_payload_extension_data, ps_bitstrm, 1);
            payload_bits_remaining--;
 }

        BITS_PARSE("payload_bit_equal_to_one", u4_dummy, ps_bitstrm, 1);
        payload_bits_remaining--;
 while(payload_bits_remaining)
 {
            BITS_PARSE("payload_bit_equal_to_zero", u4_dummy, ps_bitstrm, 1);
            payload_bits_remaining--;
 }
 }

 return;
}

In ihevcd_parse_sei_payload of ihevcd_parse_headers.c, there is a possible out-of-bounds write due to an integer overflow. This could lead to remote code execution with no additional execution privileges needed. User interaction is needed for exploitation. Product: Android Versions: Android-8.0 Android ID: A-65484460


void ihevcd_parse_sei_payload(codec_t *ps_codec,
                              UWORD32 u4_payload_type,
                              UWORD32 u4_payload_size,
                              WORD8 i1_nal_type)
{
 parse_ctxt_t *ps_parse = &ps_codec->s_parse;
 bitstrm_t *ps_bitstrm = &ps_parse->s_bitstrm;
    WORD32 payload_bits_remaining = 0;
 sps_t *ps_sps;

    UWORD32 i;

 for(i = 0; i < MAX_SPS_CNT; i++)
 {
        ps_sps = ps_codec->ps_sps_base + i;
 if(ps_sps->i1_sps_valid)
 {
 break;
 }
 }
 if(NULL == ps_sps)
 {
 return;
 }

 if(NAL_PREFIX_SEI == i1_nal_type)
 {
 switch(u4_payload_type)
 {
 case SEI_BUFFERING_PERIOD:
                ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                ihevcd_parse_buffering_period_sei(ps_codec, ps_sps);
 break;

 case SEI_PICTURE_TIMING:
                ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                ihevcd_parse_pic_timing_sei(ps_codec, ps_sps);
 break;

 case SEI_TIME_CODE:
                ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                ihevcd_parse_time_code_sei(ps_codec);
 break;

 case SEI_MASTERING_DISPLAY_COLOUR_VOLUME:
                ps_parse->s_sei_params.i4_sei_mastering_disp_colour_vol_params_present_flags = 1;
                ihevcd_parse_mastering_disp_params_sei(ps_codec);
 break;

             case SEI_USER_DATA_REGISTERED_ITU_T_T35:
                 ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                if(ps_parse->s_sei_params.i4_sei_user_data_cnt >= USER_DATA_MAX)
                {
                    for(i = 0; i < u4_payload_size / 4; i++)
                    {
                        ihevcd_bits_flush(ps_bitstrm, 4 * 8);
                    }

                    ihevcd_bits_flush(ps_bitstrm, (u4_payload_size - i * 4) * 8);
                }
                else
                {
                    ihevcd_parse_user_data_registered_itu_t_t35(ps_codec,
                                                                u4_payload_size);
                }
                 break;

             default:
 for(i = 0; i < u4_payload_size; i++)
 {
                    ihevcd_bits_flush(ps_bitstrm, 8);
 }
 break;
 }
 }
 else /* NAL_SUFFIX_SEI */
 {
 switch(u4_payload_type)

         {
             case SEI_USER_DATA_REGISTERED_ITU_T_T35:
                 ps_parse->s_sei_params.i1_sei_parameters_present_flag = 1;
                if(ps_parse->s_sei_params.i4_sei_user_data_cnt >= USER_DATA_MAX)
                {
                    for(i = 0; i < u4_payload_size / 4; i++)
                    {
                        ihevcd_bits_flush(ps_bitstrm, 4 * 8);
                    }

                    ihevcd_bits_flush(ps_bitstrm, (u4_payload_size - i * 4) * 8);
                }
                else
                {
                    ihevcd_parse_user_data_registered_itu_t_t35(ps_codec,
                                                                u4_payload_size);
                }
                 break;

             default:
 for(i = 0; i < u4_payload_size; i++)
 {
                    ihevcd_bits_flush(ps_bitstrm, 8);
 }
 break;
 }
 }

 /**
     * By definition the underlying bitstream terminates in a byte-aligned manner.
     * 1. Extract all bar the last MIN(bitsremaining,nine) bits as reserved_payload_extension_data
     * 2. Examine the final 8 bits to determine the payload_bit_equal_to_one marker
     * 3. Extract the remainingreserved_payload_extension_data bits.
     *
     * If there are fewer than 9 bits available, extract them.
     */

    payload_bits_remaining = ihevcd_bits_num_bits_remaining(ps_bitstrm);
 if(payload_bits_remaining) /* more_data_in_payload() */
 {
        WORD32 final_bits;
        WORD32 final_payload_bits = 0;
        WORD32 mask = 0xFF;
        UWORD32 u4_dummy;
        UWORD32 u4_reserved_payload_extension_data;
        UNUSED(u4_dummy);
        UNUSED(u4_reserved_payload_extension_data);

 while(payload_bits_remaining > 9)
 {
            BITS_PARSE("reserved_payload_extension_data",
                       u4_reserved_payload_extension_data, ps_bitstrm, 1);
            payload_bits_remaining--;
 }

        final_bits = ihevcd_bits_nxt(ps_bitstrm, payload_bits_remaining);

 while(final_bits & (mask >> final_payload_bits))
 {
            final_payload_bits++;
 continue;
 }

 while(payload_bits_remaining > (9 - final_payload_bits))
 {
            BITS_PARSE("reserved_payload_extension_data",
                       u4_reserved_payload_extension_data, ps_bitstrm, 1);
            payload_bits_remaining--;
 }

        BITS_PARSE("payload_bit_equal_to_one", u4_dummy, ps_bitstrm, 1);
        payload_bits_remaining--;
 while(payload_bits_remaining)
 {
            BITS_PARSE("payload_bit_equal_to_zero", u4_dummy, ps_bitstrm, 1);
            payload_bits_remaining--;
 }
 }

 return;
}


bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
 size_t oldSize = mSize;

 size_t offset = 0;
 while (mSize >= 10 && offset <= mSize - 10) {
 if (!memcmp(&mData[offset], "\0\0\0\0", 4)) {
 break;
 }

 size_t dataSize;
 if (iTunesHack) {
            dataSize = U32_AT(&mData[offset + 4]);
 } else if (!ParseSyncsafeInteger(&mData[offset + 4], &dataSize)) {
 return false;
 }

 if (dataSize > mSize - 10 - offset) {
 return false;
 }

 uint16_t flags = U16_AT(&mData[offset + 8]);
 uint16_t prevFlags = flags;

 if (flags & 1) {

 if (mSize < 14 || mSize - 14 < offset || dataSize < 4) {
 return false;
 }
            memmove(&mData[offset + 10], &mData[offset + 14], mSize - offset - 14);
            mSize -= 4;
            dataSize -= 4;

            flags &= ~1;
 }

 if ((flags & 2) && (dataSize >= 2)) {

 size_t readOffset = offset + 11;
 size_t writeOffset = offset + 11;
 for (size_t i = 0; i + 1 < dataSize; ++i) {
 if (mData[readOffset - 1] == 0xff
 && mData[readOffset] == 0x00) {
 ++readOffset;

                     --mSize;
                     --dataSize;
                 }
                mData[writeOffset++] = mData[readOffset++];
             }
             if (readOffset <= oldSize) {
                memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset);
 } else {
                ALOGE("b/34618607 (%zu %zu %zu %zu)", readOffset, writeOffset, oldSize, mSize);
                android_errorWriteLog(0x534e4554, "34618607");
 }

 }
        flags &= ~2;
 if (flags != prevFlags || iTunesHack) {
 WriteSyncsafeInteger(&mData[offset + 4], dataSize);
            mData[offset + 8] = flags >> 8;
            mData[offset + 9] = flags & 0xff;
 }

        offset += 10 + dataSize;
 }

    memset(&mData[mSize], 0, oldSize - mSize);

 return true;
}

An information disclosure vulnerability in the Android media framework (av) related to id3 unsynchronization. Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0, 8.1. Android ID: A-63100526.


bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
 size_t oldSize = mSize;

 size_t offset = 0;
 while (mSize >= 10 && offset <= mSize - 10) {
 if (!memcmp(&mData[offset], "\0\0\0\0", 4)) {
 break;
 }

 size_t dataSize;
 if (iTunesHack) {
            dataSize = U32_AT(&mData[offset + 4]);
 } else if (!ParseSyncsafeInteger(&mData[offset + 4], &dataSize)) {
 return false;
 }

 if (dataSize > mSize - 10 - offset) {
 return false;
 }

 uint16_t flags = U16_AT(&mData[offset + 8]);
 uint16_t prevFlags = flags;

 if (flags & 1) {

 if (mSize < 14 || mSize - 14 < offset || dataSize < 4) {
 return false;
 }
            memmove(&mData[offset + 10], &mData[offset + 14], mSize - offset - 14);
            mSize -= 4;
            dataSize -= 4;

            flags &= ~1;
 }

 if ((flags & 2) && (dataSize >= 2)) {

 size_t readOffset = offset + 11;
 size_t writeOffset = offset + 11;
 for (size_t i = 0; i + 1 < dataSize; ++i) {
 if (mData[readOffset - 1] == 0xff
 && mData[readOffset] == 0x00) {
 ++readOffset;

                     --mSize;
                     --dataSize;
                 }
                if (i + 1 < dataSize) {
                    // Only move data if there's actually something to move.
                    // This handles the special case of the data being only [0xff, 0x00]
                    // which should be converted to just 0xff if unsynchronization is on.
                    mData[writeOffset++] = mData[readOffset++];
                }
             }
             if (readOffset <= oldSize) {
                memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset);
 } else {
                ALOGE("b/34618607 (%zu %zu %zu %zu)", readOffset, writeOffset, oldSize, mSize);
                android_errorWriteLog(0x534e4554, "34618607");
 }

 }
        flags &= ~2;
 if (flags != prevFlags || iTunesHack) {
 WriteSyncsafeInteger(&mData[offset + 4], dataSize);
            mData[offset + 8] = flags >> 8;
            mData[offset + 9] = flags & 0xff;
 }

        offset += 10 + dataSize;
 }

    memset(&mData[mSize], 0, oldSize - mSize);

 return true;
}


long FrameSequenceState_gif::drawFrame(int frameNr,
 Color8888* outputPtr, int outputPixelStride, int previousFrameNr) {

 GifFileType* gif = mFrameSequence.getGif();
 if (!gif) {
        ALOGD("Cannot drawFrame, mGif is NULL");
 return -1;
 }

#if GIF_DEBUG
    ALOGD("      drawFrame on %p nr %d on addr %p, previous frame nr %d",
 this, frameNr, outputPtr, previousFrameNr);
#endif

 const int height = mFrameSequence.getHeight();
 const int width = mFrameSequence.getWidth();

 GraphicsControlBlock gcb;

 int start = max(previousFrameNr + 1, 0);

 for (int i = max(start - 1, 0); i < frameNr; i++) {
 int neededPreservedFrame = mFrameSequence.getRestoringFrame(i);
 if (neededPreservedFrame >= 0 && (mPreserveBufferFrame != neededPreservedFrame)) {
#if GIF_DEBUG
            ALOGD("frame %d needs frame %d preserved, but %d is currently, so drawing from scratch",
                    i, neededPreservedFrame, mPreserveBufferFrame);
#endif
            start = 0;
 }
 }

 for (int i = start; i <= frameNr; i++) {
 DGifSavedExtensionToGCB(gif, i, &gcb);
 const SavedImage& frame = gif->SavedImages[i];

#if GIF_DEBUG
 bool frameOpaque = gcb.TransparentColor == NO_TRANSPARENT_COLOR;
        ALOGD("producing frame %d, drawing frame %d (opaque %d, disp %d, del %d)",
                frameNr, i, frameOpaque, gcb.DisposalMode, gcb.DelayTime);
#endif
 if (i == 0) {
 Color8888 bgColor = mFrameSequence.getBackgroundColor();
 for (int y = 0; y < height; y++) {
 for (int x = 0; x < width; x++) {
                    outputPtr[y * outputPixelStride + x] = bgColor;
 }
 }
 } else {
 GraphicsControlBlock prevGcb;
 DGifSavedExtensionToGCB(gif, i - 1, &prevGcb);
 const SavedImage& prevFrame = gif->SavedImages[i - 1];
 bool prevFrameDisposed = willBeCleared(prevGcb);

 bool newFrameOpaque = gcb.TransparentColor == NO_TRANSPARENT_COLOR;
 bool prevFrameCompletelyCovered = newFrameOpaque
 && checkIfCover(frame.ImageDesc, prevFrame.ImageDesc);

 if (prevFrameDisposed && !prevFrameCompletelyCovered) {
 switch (prevGcb.DisposalMode) {
 case DISPOSE_BACKGROUND: {
 Color8888* dst = outputPtr + prevFrame.ImageDesc.Left +
                            prevFrame.ImageDesc.Top * outputPixelStride;

 GifWord copyWidth, copyHeight;
                    getCopySize(prevFrame.ImageDesc, width, height, copyWidth, copyHeight);
 for (; copyHeight > 0; copyHeight--) {
                        setLineColor(dst, TRANSPARENT, copyWidth);
                        dst += outputPixelStride;
 }
 } break;
 case DISPOSE_PREVIOUS: {
                    restorePreserveBuffer(outputPtr, outputPixelStride);
 } break;
 }
 }

 if (mFrameSequence.getPreservedFrame(i - 1)) {
                savePreserveBuffer(outputPtr, outputPixelStride, i - 1);
 }
 }

 bool willBeCleared = gcb.DisposalMode == DISPOSE_BACKGROUND
 || gcb.DisposalMode == DISPOSE_PREVIOUS;
 if (i == frameNr || !willBeCleared) {
 const ColorMapObject* cmap = gif->SColorMap;
 if (frame.ImageDesc.ColorMap) {

                 cmap = frame.ImageDesc.ColorMap;
             }

            if (cmap == NULL || cmap->ColorCount != (1 << cmap->BitsPerPixel)) {
                ALOGW("Warning: potentially corrupt color map");
            }
            const unsigned char* src = (unsigned char*)frame.RasterBits;
            Color8888* dst = outputPtr + frame.ImageDesc.Left +
                    frame.ImageDesc.Top * outputPixelStride;
            GifWord copyWidth, copyHeight;
            getCopySize(frame.ImageDesc, width, height, copyWidth, copyHeight);
            for (; copyHeight > 0; copyHeight--) {
                copyLine(dst, src, cmap, gcb.TransparentColor, copyWidth);
                src += frame.ImageDesc.Width;
                dst += outputPixelStride;
             }
         }
     }

 const int maxFrame = gif->ImageCount;
 const int lastFrame = (frameNr + maxFrame - 1) % maxFrame;
 DGifSavedExtensionToGCB(gif, lastFrame, &gcb);
 return getDelayMs(gcb);
}

A vulnerability in the Android media framework (ex) related to composition of frames lacking a color map. Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0, 8.1. Android ID: A-68399117.


long FrameSequenceState_gif::drawFrame(int frameNr,
 Color8888* outputPtr, int outputPixelStride, int previousFrameNr) {

 GifFileType* gif = mFrameSequence.getGif();
 if (!gif) {
        ALOGD("Cannot drawFrame, mGif is NULL");
 return -1;
 }

#if GIF_DEBUG
    ALOGD("      drawFrame on %p nr %d on addr %p, previous frame nr %d",
 this, frameNr, outputPtr, previousFrameNr);
#endif

 const int height = mFrameSequence.getHeight();
 const int width = mFrameSequence.getWidth();

 GraphicsControlBlock gcb;

 int start = max(previousFrameNr + 1, 0);

 for (int i = max(start - 1, 0); i < frameNr; i++) {
 int neededPreservedFrame = mFrameSequence.getRestoringFrame(i);
 if (neededPreservedFrame >= 0 && (mPreserveBufferFrame != neededPreservedFrame)) {
#if GIF_DEBUG
            ALOGD("frame %d needs frame %d preserved, but %d is currently, so drawing from scratch",
                    i, neededPreservedFrame, mPreserveBufferFrame);
#endif
            start = 0;
 }
 }

 for (int i = start; i <= frameNr; i++) {
 DGifSavedExtensionToGCB(gif, i, &gcb);
 const SavedImage& frame = gif->SavedImages[i];

#if GIF_DEBUG
 bool frameOpaque = gcb.TransparentColor == NO_TRANSPARENT_COLOR;
        ALOGD("producing frame %d, drawing frame %d (opaque %d, disp %d, del %d)",
                frameNr, i, frameOpaque, gcb.DisposalMode, gcb.DelayTime);
#endif
 if (i == 0) {
 Color8888 bgColor = mFrameSequence.getBackgroundColor();
 for (int y = 0; y < height; y++) {
 for (int x = 0; x < width; x++) {
                    outputPtr[y * outputPixelStride + x] = bgColor;
 }
 }
 } else {
 GraphicsControlBlock prevGcb;
 DGifSavedExtensionToGCB(gif, i - 1, &prevGcb);
 const SavedImage& prevFrame = gif->SavedImages[i - 1];
 bool prevFrameDisposed = willBeCleared(prevGcb);

 bool newFrameOpaque = gcb.TransparentColor == NO_TRANSPARENT_COLOR;
 bool prevFrameCompletelyCovered = newFrameOpaque
 && checkIfCover(frame.ImageDesc, prevFrame.ImageDesc);

 if (prevFrameDisposed && !prevFrameCompletelyCovered) {
 switch (prevGcb.DisposalMode) {
 case DISPOSE_BACKGROUND: {
 Color8888* dst = outputPtr + prevFrame.ImageDesc.Left +
                            prevFrame.ImageDesc.Top * outputPixelStride;

 GifWord copyWidth, copyHeight;
                    getCopySize(prevFrame.ImageDesc, width, height, copyWidth, copyHeight);
 for (; copyHeight > 0; copyHeight--) {
                        setLineColor(dst, TRANSPARENT, copyWidth);
                        dst += outputPixelStride;
 }
 } break;
 case DISPOSE_PREVIOUS: {
                    restorePreserveBuffer(outputPtr, outputPixelStride);
 } break;
 }
 }

 if (mFrameSequence.getPreservedFrame(i - 1)) {
                savePreserveBuffer(outputPtr, outputPixelStride, i - 1);
 }
 }

 bool willBeCleared = gcb.DisposalMode == DISPOSE_BACKGROUND
 || gcb.DisposalMode == DISPOSE_PREVIOUS;
 if (i == frameNr || !willBeCleared) {
 const ColorMapObject* cmap = gif->SColorMap;
 if (frame.ImageDesc.ColorMap) {

                 cmap = frame.ImageDesc.ColorMap;
             }

            // If a cmap is missing, the frame can't be decoded, so we skip it.
            if (cmap) {
                const unsigned char* src = (unsigned char*)frame.RasterBits;
                Color8888* dst = outputPtr + frame.ImageDesc.Left +
                        frame.ImageDesc.Top * outputPixelStride;
                GifWord copyWidth, copyHeight;
                getCopySize(frame.ImageDesc, width, height, copyWidth, copyHeight);
                for (; copyHeight > 0; copyHeight--) {
                    copyLine(dst, src, cmap, gcb.TransparentColor, copyWidth);
                    src += frame.ImageDesc.Width;
                    dst += outputPixelStride;
                }
             }
         }
     }

 const int maxFrame = gif->ImageCount;
 const int lastFrame = (frameNr + maxFrame - 1) % maxFrame;
 DGifSavedExtensionToGCB(gif, lastFrame, &gcb);
 return getDelayMs(gcb);
}


static vpx_image_t *img_alloc_helper(vpx_image_t *img, vpx_img_fmt_t fmt,
 unsigned int d_w, unsigned int d_h,
 unsigned int buf_align,
 unsigned int stride_align,
 unsigned char *img_data) {
 unsigned int h, w, s, xcs, ycs, bps;
 unsigned int stride_in_bytes;
 int align;

 /* Treat align==0 like align==1 */
 if (!buf_align) buf_align = 1;

 /* Validate alignment (must be power of 2) */
 if (buf_align & (buf_align - 1)) goto fail;

 /* Treat align==0 like align==1 */
 if (!stride_align) stride_align = 1;

 /* Validate alignment (must be power of 2) */
 if (stride_align & (stride_align - 1)) goto fail;

 /* Get sample size for this format */
 switch (fmt) {
 case VPX_IMG_FMT_RGB32:
 case VPX_IMG_FMT_RGB32_LE:
 case VPX_IMG_FMT_ARGB:
 case VPX_IMG_FMT_ARGB_LE: bps = 32; break;
 case VPX_IMG_FMT_RGB24:
 case VPX_IMG_FMT_BGR24: bps = 24; break;
 case VPX_IMG_FMT_RGB565:
 case VPX_IMG_FMT_RGB565_LE:
 case VPX_IMG_FMT_RGB555:
 case VPX_IMG_FMT_RGB555_LE:
 case VPX_IMG_FMT_UYVY:
 case VPX_IMG_FMT_YUY2:
 case VPX_IMG_FMT_YVYU: bps = 16; break;
 case VPX_IMG_FMT_I420:
 case VPX_IMG_FMT_YV12:
 case VPX_IMG_FMT_VPXI420:
 case VPX_IMG_FMT_VPXYV12: bps = 12; break;
 case VPX_IMG_FMT_I422:
 case VPX_IMG_FMT_I440: bps = 16; break;
 case VPX_IMG_FMT_I444: bps = 24; break;
 case VPX_IMG_FMT_I42016: bps = 24; break;
 case VPX_IMG_FMT_I42216:
 case VPX_IMG_FMT_I44016: bps = 32; break;
 case VPX_IMG_FMT_I44416: bps = 48; break;
 default: bps = 16; break;
 }

 /* Get chroma shift values for this format */
 switch (fmt) {
 case VPX_IMG_FMT_I420:
 case VPX_IMG_FMT_YV12:
 case VPX_IMG_FMT_VPXI420:
 case VPX_IMG_FMT_VPXYV12:
 case VPX_IMG_FMT_I422:
 case VPX_IMG_FMT_I42016:
 case VPX_IMG_FMT_I42216: xcs = 1; break;
 default: xcs = 0; break;
 }

 switch (fmt) {
 case VPX_IMG_FMT_I420:
 case VPX_IMG_FMT_I440:
 case VPX_IMG_FMT_YV12:
 case VPX_IMG_FMT_VPXI420:
 case VPX_IMG_FMT_VPXYV12:
 case VPX_IMG_FMT_I42016:
 case VPX_IMG_FMT_I44016: ycs = 1; break;

     default: ycs = 0; break;
   }

  /* Calculate storage sizes given the chroma subsampling */
  align = (1 << xcs) - 1;
  w = (d_w + align) & ~align;
  align = (1 << ycs) - 1;
  h = (d_h + align) & ~align;
   s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
   s = (s + stride_align - 1) & ~(stride_align - 1);
   stride_in_bytes = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s;

 /* Allocate the new image */
 if (!img) {
    img = (vpx_image_t *)calloc(1, sizeof(vpx_image_t));

 if (!img) goto fail;

    img->self_allocd = 1;
 } else {
    memset(img, 0, sizeof(vpx_image_t));
 }

   img->img_data = img_data;

   if (!img_data) {
    const uint64_t alloc_size = (fmt & VPX_IMG_FMT_PLANAR)
                                    ? (uint64_t)h * s * bps / 8
                                    : (uint64_t)h * s;

     if (alloc_size != (size_t)alloc_size) goto fail;

    img->img_data = (uint8_t *)vpx_memalign(buf_align, (size_t)alloc_size);
    img->img_data_owner = 1;
 }

 if (!img->img_data) goto fail;

  img->fmt = fmt;
  img->bit_depth = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
  img->w = w;
  img->h = h;
  img->x_chroma_shift = xcs;
  img->y_chroma_shift = ycs;
  img->bps = bps;

 /* Calculate strides */
  img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = stride_in_bytes;
  img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = stride_in_bytes >> xcs;

 /* Default viewport to entire image */
 if (!vpx_img_set_rect(img, 0, 0, d_w, d_h)) return img;

fail:
  vpx_img_free(img);
 return NULL;
}

A vulnerability in the Android media framework (libvpx) related to odd frame width. Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0, 8.1. Android ID: A-64710201.


static vpx_image_t *img_alloc_helper(vpx_image_t *img, vpx_img_fmt_t fmt,
 unsigned int d_w, unsigned int d_h,
 unsigned int buf_align,
 unsigned int stride_align,
 unsigned char *img_data) {
 unsigned int h, w, s, xcs, ycs, bps;
 unsigned int stride_in_bytes;
 int align;

 /* Treat align==0 like align==1 */
 if (!buf_align) buf_align = 1;

 /* Validate alignment (must be power of 2) */
 if (buf_align & (buf_align - 1)) goto fail;

 /* Treat align==0 like align==1 */
 if (!stride_align) stride_align = 1;

 /* Validate alignment (must be power of 2) */
 if (stride_align & (stride_align - 1)) goto fail;

 /* Get sample size for this format */
 switch (fmt) {
 case VPX_IMG_FMT_RGB32:
 case VPX_IMG_FMT_RGB32_LE:
 case VPX_IMG_FMT_ARGB:
 case VPX_IMG_FMT_ARGB_LE: bps = 32; break;
 case VPX_IMG_FMT_RGB24:
 case VPX_IMG_FMT_BGR24: bps = 24; break;
 case VPX_IMG_FMT_RGB565:
 case VPX_IMG_FMT_RGB565_LE:
 case VPX_IMG_FMT_RGB555:
 case VPX_IMG_FMT_RGB555_LE:
 case VPX_IMG_FMT_UYVY:
 case VPX_IMG_FMT_YUY2:
 case VPX_IMG_FMT_YVYU: bps = 16; break;
 case VPX_IMG_FMT_I420:
 case VPX_IMG_FMT_YV12:
 case VPX_IMG_FMT_VPXI420:
 case VPX_IMG_FMT_VPXYV12: bps = 12; break;
 case VPX_IMG_FMT_I422:
 case VPX_IMG_FMT_I440: bps = 16; break;
 case VPX_IMG_FMT_I444: bps = 24; break;
 case VPX_IMG_FMT_I42016: bps = 24; break;
 case VPX_IMG_FMT_I42216:
 case VPX_IMG_FMT_I44016: bps = 32; break;
 case VPX_IMG_FMT_I44416: bps = 48; break;
 default: bps = 16; break;
 }

 /* Get chroma shift values for this format */
 switch (fmt) {
 case VPX_IMG_FMT_I420:
 case VPX_IMG_FMT_YV12:
 case VPX_IMG_FMT_VPXI420:
 case VPX_IMG_FMT_VPXYV12:
 case VPX_IMG_FMT_I422:
 case VPX_IMG_FMT_I42016:
 case VPX_IMG_FMT_I42216: xcs = 1; break;
 default: xcs = 0; break;
 }

 switch (fmt) {
 case VPX_IMG_FMT_I420:
 case VPX_IMG_FMT_I440:
 case VPX_IMG_FMT_YV12:
 case VPX_IMG_FMT_VPXI420:
 case VPX_IMG_FMT_VPXYV12:
 case VPX_IMG_FMT_I42016:
 case VPX_IMG_FMT_I44016: ycs = 1; break;

     default: ycs = 0; break;
   }

  /* Calculate storage sizes. If the buffer was allocated externally, the width
   * and height shouldn't be adjusted. */
  w = d_w;
  h = d_h;
   s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
   s = (s + stride_align - 1) & ~(stride_align - 1);
   stride_in_bytes = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s;

 /* Allocate the new image */
 if (!img) {
    img = (vpx_image_t *)calloc(1, sizeof(vpx_image_t));

 if (!img) goto fail;

    img->self_allocd = 1;
 } else {
    memset(img, 0, sizeof(vpx_image_t));
 }

   img->img_data = img_data;

   if (!img_data) {
    uint64_t alloc_size;
    /* Calculate storage sizes given the chroma subsampling */
    align = (1 << xcs) - 1;
    w = (d_w + align) & ~align;
    align = (1 << ycs) - 1;
    h = (d_h + align) & ~align;

    s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
    s = (s + stride_align - 1) & ~(stride_align - 1);
    stride_in_bytes = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s;
    alloc_size = (fmt & VPX_IMG_FMT_PLANAR) ? (uint64_t)h * s * bps / 8
                                            : (uint64_t)h * s;

     if (alloc_size != (size_t)alloc_size) goto fail;

    img->img_data = (uint8_t *)vpx_memalign(buf_align, (size_t)alloc_size);
    img->img_data_owner = 1;
 }

 if (!img->img_data) goto fail;

  img->fmt = fmt;
  img->bit_depth = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
  img->w = w;
  img->h = h;
  img->x_chroma_shift = xcs;
  img->y_chroma_shift = ycs;
  img->bps = bps;

 /* Calculate strides */
  img->stride[VPX_PLANE_Y] = img->stride[VPX_PLANE_ALPHA] = stride_in_bytes;
  img->stride[VPX_PLANE_U] = img->stride[VPX_PLANE_V] = stride_in_bytes >> xcs;

 /* Default viewport to entire image */
 if (!vpx_img_set_rect(img, 0, 0, d_w, d_h)) return img;

fail:
  vpx_img_free(img);
 return NULL;
}


WORD32 ihevcd_create(iv_obj_t *ps_codec_obj,

                            void *pv_api_ip,
                            void *pv_api_op)
 {
     ihevcd_cxa_create_op_t *ps_create_op;

     WORD32 ret;
     codec_t *ps_codec;
     ps_create_op = (ihevcd_cxa_create_op_t *)pv_api_op;

     ps_create_op->s_ivd_create_op_t.u4_error_code = 0;
     ret = ihevcd_allocate_static_bufs(&ps_codec_obj, pv_api_ip, pv_api_op);

     /* If allocation of some buffer fails, then free buffers allocated till then */
    if((IV_FAIL == ret) && (NULL != ps_codec_obj))
     {
        ihevcd_free_static_bufs(ps_codec_obj);
         ps_create_op->s_ivd_create_op_t.u4_error_code = IVD_MEM_ALLOC_FAILED;
         ps_create_op->s_ivd_create_op_t.u4_error_code = 1 << IVD_FATALERROR;

 return IV_FAIL;
 }
    ps_codec = (codec_t *)ps_codec_obj->pv_codec_handle;
    ret = ihevcd_init(ps_codec);

    TRACE_INIT(NULL);
    STATS_INIT();

 return ret;
}

A vulnerability in the Android media framework (libhevc) related to handling ps_codec_obj memory allocation failures. Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0, 8.1. Android ID: A-68299873.


WORD32 ihevcd_create(iv_obj_t *ps_codec_obj,

                            void *pv_api_ip,
                            void *pv_api_op)
 {
    ihevcd_cxa_create_ip_t *ps_create_ip;
     ihevcd_cxa_create_op_t *ps_create_op;

     WORD32 ret;
     codec_t *ps_codec;
    ps_create_ip = (ihevcd_cxa_create_ip_t *)pv_api_ip;
     ps_create_op = (ihevcd_cxa_create_op_t *)pv_api_op;

     ps_create_op->s_ivd_create_op_t.u4_error_code = 0;
    ps_codec_obj = NULL;
     ret = ihevcd_allocate_static_bufs(&ps_codec_obj, pv_api_ip, pv_api_op);

     /* If allocation of some buffer fails, then free buffers allocated till then */
    if(IV_FAIL == ret)
     {
        if(NULL != ps_codec_obj)
        {
            if(ps_codec_obj->pv_codec_handle)
            {
                ihevcd_free_static_bufs(ps_codec_obj);
            }
            else
            {
                void (*pf_aligned_free)(void *pv_mem_ctxt, void *pv_buf);
                void *pv_mem_ctxt;

                pf_aligned_free = ps_create_ip->s_ivd_create_ip_t.pf_aligned_free;
                pv_mem_ctxt  = ps_create_ip->s_ivd_create_ip_t.pv_mem_ctxt;
                pf_aligned_free(pv_mem_ctxt, ps_codec_obj);
            }
        }
         ps_create_op->s_ivd_create_op_t.u4_error_code = IVD_MEM_ALLOC_FAILED;
         ps_create_op->s_ivd_create_op_t.u4_error_code = 1 << IVD_FATALERROR;

 return IV_FAIL;
 }
    ps_codec = (codec_t *)ps_codec_obj->pv_codec_handle;
    ret = ihevcd_init(ps_codec);

    TRACE_INIT(NULL);
    STATS_INIT();

 return ret;
}


 WORD32 ih264d_create(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
 {
     ih264d_create_op_t *ps_create_op;

     WORD32 ret;

     ps_create_op = (ih264d_create_op_t *)pv_api_op;

     ps_create_op->s_ivd_create_op_t.u4_error_code = 0;
     ret = ih264d_allocate_static_bufs(&dec_hdl, pv_api_ip, pv_api_op);

     /* If allocation of some buffer fails, then free buffers allocated till then */
    if((IV_FAIL == ret) && (NULL != dec_hdl))
     {
        ih264d_free_static_bufs(dec_hdl);
         ps_create_op->s_ivd_create_op_t.u4_error_code = IVD_MEM_ALLOC_FAILED;
         ps_create_op->s_ivd_create_op_t.u4_error_code = 1 << IVD_FATALERROR;

 return IV_FAIL;
 }

 return IV_SUCCESS;
}

A vulnerability in the Android media framework (libavc) related to handling dec_hdl memory allocation failures. Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0, 8.1. Android ID: A-68300072.


 WORD32 ih264d_create(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
 {
    ih264d_create_ip_t *ps_create_ip;
     ih264d_create_op_t *ps_create_op;

     WORD32 ret;

    ps_create_ip = (ih264d_create_ip_t *)pv_api_ip;
     ps_create_op = (ih264d_create_op_t *)pv_api_op;

     ps_create_op->s_ivd_create_op_t.u4_error_code = 0;
    dec_hdl = NULL;
     ret = ih264d_allocate_static_bufs(&dec_hdl, pv_api_ip, pv_api_op);

     /* If allocation of some buffer fails, then free buffers allocated till then */
    if(IV_FAIL == ret)
     {
        if(dec_hdl)
        {
            if(dec_hdl->pv_codec_handle)
            {
                ih264d_free_static_bufs(dec_hdl);
            }
            else
            {
                void (*pf_aligned_free)(void *pv_mem_ctxt, void *pv_buf);
                void *pv_mem_ctxt;

                pf_aligned_free = ps_create_ip->s_ivd_create_ip_t.pf_aligned_free;
                pv_mem_ctxt  = ps_create_ip->s_ivd_create_ip_t.pv_mem_ctxt;
                pf_aligned_free(pv_mem_ctxt, dec_hdl);
            }
        }
         ps_create_op->s_ivd_create_op_t.u4_error_code = IVD_MEM_ALLOC_FAILED;
         ps_create_op->s_ivd_create_op_t.u4_error_code = 1 << IVD_FATALERROR;

 return IV_FAIL;
 }

 return IV_SUCCESS;
}


IHEVCD_ERROR_T ihevcd_parse_slice_header(codec_t *ps_codec,
 nal_header_t *ps_nal)
{
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    WORD32 value;
    WORD32 i, j;
    WORD32 sps_id;

 pps_t *ps_pps;
 sps_t *ps_sps;
 slice_header_t *ps_slice_hdr;
    WORD32 disable_deblocking_filter_flag;
 bitstrm_t *ps_bitstrm = &ps_codec->s_parse.s_bitstrm;
    WORD32 idr_pic_flag;
    WORD32 pps_id;
    WORD32 first_slice_in_pic_flag;
    WORD32 no_output_of_prior_pics_flag = 0;

     WORD8 i1_nal_unit_type = ps_nal->i1_nal_unit_type;
     WORD32 num_poc_total_curr = 0;
     WORD32 slice_address;

     if(ps_codec->i4_slice_error == 1)
         return ret;

    idr_pic_flag = (NAL_IDR_W_LP == i1_nal_unit_type) ||
 (NAL_IDR_N_LP == i1_nal_unit_type);

    BITS_PARSE("first_slice_in_pic_flag", first_slice_in_pic_flag, ps_bitstrm, 1);
 if((NAL_BLA_W_LP <= i1_nal_unit_type) &&
 (NAL_RSV_RAP_VCL23          >= i1_nal_unit_type))
 {
        BITS_PARSE("no_output_of_prior_pics_flag", no_output_of_prior_pics_flag, ps_bitstrm, 1);
 }
    UEV_PARSE("pic_parameter_set_id", pps_id, ps_bitstrm);
    pps_id = CLIP3(pps_id, 0, MAX_PPS_CNT - 2);

 /* Get the current PPS structure */
    ps_pps = ps_codec->s_parse.ps_pps_base + pps_id;
 if(0 == ps_pps->i1_pps_valid)
 {
 pps_t *ps_pps_ref = ps_codec->ps_pps_base;
 while(0 == ps_pps_ref->i1_pps_valid)
 {
            ps_pps_ref++;
 if((ps_pps_ref - ps_codec->ps_pps_base >= MAX_PPS_CNT - 1))
 return IHEVCD_INVALID_HEADER;
 }

        ihevcd_copy_pps(ps_codec, pps_id, ps_pps_ref->i1_pps_id);
 }

 /* Get SPS id for the current PPS */
    sps_id = ps_pps->i1_sps_id;

 /* Get the current SPS structure */
    ps_sps = ps_codec->s_parse.ps_sps_base + sps_id;

 /* When the current slice is the first in a pic,
     *  check whether the previous frame is complete
     *  If the previous frame is incomplete -
     *  treat the remaining CTBs as skip */
 if((0 != ps_codec->u4_pic_cnt || ps_codec->i4_pic_present) &&
                    first_slice_in_pic_flag)
 {
 if(ps_codec->i4_pic_present)
 {
 slice_header_t *ps_slice_hdr_next;
            ps_codec->i4_slice_error = 1;
            ps_codec->s_parse.i4_cur_slice_idx--;
 if(ps_codec->s_parse.i4_cur_slice_idx < 0)
                ps_codec->s_parse.i4_cur_slice_idx = 0;

            ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + ((ps_codec->s_parse.i4_cur_slice_idx + 1) & (MAX_SLICE_HDR_CNT - 1));
            ps_slice_hdr_next->i2_ctb_x = 0;
            ps_slice_hdr_next->i2_ctb_y = ps_codec->s_parse.ps_sps->i2_pic_ht_in_ctb;
 return ret;
 }
 else
 {
            ps_codec->i4_slice_error = 0;
 }
 }

 if(first_slice_in_pic_flag)
 {
        ps_codec->s_parse.i4_cur_slice_idx = 0;
 }
 else
 {
 /* If the current slice is not the first slice in the pic,
         * but the first one to be parsed, set the current slice indx to 1
         * Treat the first slice to be missing and copy the current slice header
         * to the first one */
 if(0 == ps_codec->i4_pic_present)
            ps_codec->s_parse.i4_cur_slice_idx = 1;
 }

    ps_slice_hdr = ps_codec->s_parse.ps_slice_hdr_base + (ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1));

 if((ps_pps->i1_dependent_slice_enabled_flag) &&
 (!first_slice_in_pic_flag))
 {
        BITS_PARSE("dependent_slice_flag", value, ps_bitstrm, 1);

 /* If dependendent slice, copy slice header from previous slice */
 if(value && (ps_codec->s_parse.i4_cur_slice_idx > 0))
 {
            ihevcd_copy_slice_hdr(ps_codec,
 (ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1)),
 ((ps_codec->s_parse.i4_cur_slice_idx - 1) & (MAX_SLICE_HDR_CNT - 1)));
 }
        ps_slice_hdr->i1_dependent_slice_flag = value;
 }
 else
 {
        ps_slice_hdr->i1_dependent_slice_flag = 0;
 }
    ps_slice_hdr->i1_nal_unit_type = i1_nal_unit_type;
    ps_slice_hdr->i1_pps_id = pps_id;
    ps_slice_hdr->i1_first_slice_in_pic_flag = first_slice_in_pic_flag;

    ps_slice_hdr->i1_no_output_of_prior_pics_flag = 1;
 if((NAL_BLA_W_LP <= i1_nal_unit_type) &&
 (NAL_RSV_RAP_VCL23          >= i1_nal_unit_type))
 {
        ps_slice_hdr->i1_no_output_of_prior_pics_flag = no_output_of_prior_pics_flag;
 }
    ps_slice_hdr->i1_pps_id = pps_id;

 if(!ps_slice_hdr->i1_first_slice_in_pic_flag)
 {
        WORD32 num_bits;

 /* Use CLZ to compute Ceil( Log2( PicSizeInCtbsY ) ) */
        num_bits = 32 - CLZ(ps_sps->i4_pic_size_in_ctb - 1);
        BITS_PARSE("slice_address", value, ps_bitstrm, num_bits);

        slice_address = value;
 /* If slice address is greater than the number of CTBs in a picture,
         * ignore the slice */
 if(value >= ps_sps->i4_pic_size_in_ctb)
 return IHEVCD_IGNORE_SLICE;
 }
 else
 {
        slice_address = 0;
 }

 if(!ps_slice_hdr->i1_dependent_slice_flag)
 {
        ps_slice_hdr->i1_pic_output_flag = 1;
        ps_slice_hdr->i4_pic_order_cnt_lsb = 0;
        ps_slice_hdr->i1_num_long_term_sps = 0;
        ps_slice_hdr->i1_num_long_term_pics = 0;

 for(i = 0; i < ps_pps->i1_num_extra_slice_header_bits; i++)
 {
            BITS_PARSE("slice_reserved_undetermined_flag[ i ]", value, ps_bitstrm, 1);
 }
        UEV_PARSE("slice_type", value, ps_bitstrm);
        ps_slice_hdr->i1_slice_type = value;

 /* If the picture is IRAP, slice type must be equal to ISLICE */
 if((ps_slice_hdr->i1_nal_unit_type >= NAL_BLA_W_LP) &&
 (ps_slice_hdr->i1_nal_unit_type <= NAL_RSV_RAP_VCL23))
            ps_slice_hdr->i1_slice_type = ISLICE;

 if((ps_slice_hdr->i1_slice_type < 0) ||
 (ps_slice_hdr->i1_slice_type > 2))
 return IHEVCD_IGNORE_SLICE;

 if(ps_pps->i1_output_flag_present_flag)
 {
            BITS_PARSE("pic_output_flag", value, ps_bitstrm, 1);
            ps_slice_hdr->i1_pic_output_flag = value;
 }
        ps_slice_hdr->i1_colour_plane_id = 0;
 if(1 == ps_sps->i1_separate_colour_plane_flag)
 {
            BITS_PARSE("colour_plane_id", value, ps_bitstrm, 2);
            ps_slice_hdr->i1_colour_plane_id = value;
 }
        ps_slice_hdr->i1_slice_temporal_mvp_enable_flag = 0;

 if(!idr_pic_flag)
 {

            WORD32 st_rps_idx;
            WORD32 num_neg_pics;
            WORD32 num_pos_pics;
            WORD8 *pi1_used;

            BITS_PARSE("pic_order_cnt_lsb", value, ps_bitstrm, ps_sps->i1_log2_max_pic_order_cnt_lsb);
            ps_slice_hdr->i4_pic_order_cnt_lsb = value;

            BITS_PARSE("short_term_ref_pic_set_sps_flag", value, ps_bitstrm, 1);
            ps_slice_hdr->i1_short_term_ref_pic_set_sps_flag = value;

 if(1 == ps_slice_hdr->i1_short_term_ref_pic_set_sps_flag)
 {
                WORD32 numbits;

                ps_slice_hdr->i1_short_term_ref_pic_set_idx = 0;
 if(ps_sps->i1_num_short_term_ref_pic_sets > 1)
 {
                    numbits = 32 - CLZ(ps_sps->i1_num_short_term_ref_pic_sets - 1);
                    BITS_PARSE("short_term_ref_pic_set_idx", value, ps_bitstrm, numbits);
                    ps_slice_hdr->i1_short_term_ref_pic_set_idx = value;
 }

                st_rps_idx = ps_slice_hdr->i1_short_term_ref_pic_set_idx;
                num_neg_pics = ps_sps->as_stref_picset[st_rps_idx].i1_num_neg_pics;
                num_pos_pics = ps_sps->as_stref_picset[st_rps_idx].i1_num_pos_pics;
                pi1_used = ps_sps->as_stref_picset[st_rps_idx].ai1_used;
 }
 else
 {
                ihevcd_short_term_ref_pic_set(ps_bitstrm,
 &ps_sps->as_stref_picset[0],
                                              ps_sps->i1_num_short_term_ref_pic_sets,
                                              ps_sps->i1_num_short_term_ref_pic_sets,
 &ps_slice_hdr->s_stref_picset);

                st_rps_idx = ps_sps->i1_num_short_term_ref_pic_sets;
                num_neg_pics = ps_slice_hdr->s_stref_picset.i1_num_neg_pics;
                num_pos_pics = ps_slice_hdr->s_stref_picset.i1_num_pos_pics;
                pi1_used = ps_slice_hdr->s_stref_picset.ai1_used;
 }

 if(ps_sps->i1_long_term_ref_pics_present_flag)
 {
 if(ps_sps->i1_num_long_term_ref_pics_sps > 0)
 {
                    UEV_PARSE("num_long_term_sps", value, ps_bitstrm);
                    ps_slice_hdr->i1_num_long_term_sps = value;

                    ps_slice_hdr->i1_num_long_term_sps = CLIP3(ps_slice_hdr->i1_num_long_term_sps,
 0, MAX_DPB_SIZE - num_neg_pics - num_pos_pics);
 }
                UEV_PARSE("num_long_term_pics", value, ps_bitstrm);
                ps_slice_hdr->i1_num_long_term_pics = value;
                ps_slice_hdr->i1_num_long_term_pics = CLIP3(ps_slice_hdr->i1_num_long_term_pics,
 0, MAX_DPB_SIZE - num_neg_pics - num_pos_pics -
                                                            ps_slice_hdr->i1_num_long_term_sps);

 for(i = 0; i < (ps_slice_hdr->i1_num_long_term_sps +
                                ps_slice_hdr->i1_num_long_term_pics); i++)
 {
 if(i < ps_slice_hdr->i1_num_long_term_sps)
 {
 /* Use CLZ to compute Ceil( Log2( num_long_term_ref_pics_sps ) ) */
 if (ps_sps->i1_num_long_term_ref_pics_sps > 1)
 {
                            WORD32 num_bits = 32 - CLZ(ps_sps->i1_num_long_term_ref_pics_sps - 1);
                            BITS_PARSE("lt_idx_sps[ i ]", value, ps_bitstrm, num_bits);
 }
 else
 {
                            value = 0;
 }
                        ps_slice_hdr->ai4_poc_lsb_lt[i] = ps_sps->au2_lt_ref_pic_poc_lsb_sps[value];
                        ps_slice_hdr->ai1_used_by_curr_pic_lt_flag[i] = ps_sps->ai1_used_by_curr_pic_lt_sps_flag[value];

 }
 else
 {
                        BITS_PARSE("poc_lsb_lt[ i ]", value, ps_bitstrm, ps_sps->i1_log2_max_pic_order_cnt_lsb);
                        ps_slice_hdr->ai4_poc_lsb_lt[i] = value;

                        BITS_PARSE("used_by_curr_pic_lt_flag[ i ]", value, ps_bitstrm, 1);
                        ps_slice_hdr->ai1_used_by_curr_pic_lt_flag[i] = value;

 }
                    BITS_PARSE("delta_poc_msb_present_flag[ i ]", value, ps_bitstrm, 1);
                    ps_slice_hdr->ai1_delta_poc_msb_present_flag[i] = value;

                    ps_slice_hdr->ai1_delta_poc_msb_cycle_lt[i] = 0;
 if(ps_slice_hdr->ai1_delta_poc_msb_present_flag[i])
 {

                        UEV_PARSE("delata_poc_msb_cycle_lt[ i ]", value, ps_bitstrm);
                        ps_slice_hdr->ai1_delta_poc_msb_cycle_lt[i] = value;
 }

 if((i != 0) && (i != ps_slice_hdr->i1_num_long_term_sps))
 {
                        ps_slice_hdr->ai1_delta_poc_msb_cycle_lt[i] += ps_slice_hdr->ai1_delta_poc_msb_cycle_lt[i - 1];
 }

 }
 }

 for(i = 0; i < num_neg_pics + num_pos_pics; i++)
 {
 if(pi1_used[i])
 {
                    num_poc_total_curr++;
 }
 }
 for(i = 0; i < ps_slice_hdr->i1_num_long_term_sps + ps_slice_hdr->i1_num_long_term_pics; i++)
 {
 if(ps_slice_hdr->ai1_used_by_curr_pic_lt_flag[i])
 {
                    num_poc_total_curr++;
 }
 }

 if(ps_sps->i1_sps_temporal_mvp_enable_flag)
 {
                BITS_PARSE("enable_temporal_mvp_flag", value, ps_bitstrm, 1);
                ps_slice_hdr->i1_slice_temporal_mvp_enable_flag = value;
 }

 }
        ps_slice_hdr->i1_slice_sao_luma_flag = 0;
        ps_slice_hdr->i1_slice_sao_chroma_flag = 0;
 if(ps_sps->i1_sample_adaptive_offset_enabled_flag)
 {
            BITS_PARSE("slice_sao_luma_flag", value, ps_bitstrm, 1);
            ps_slice_hdr->i1_slice_sao_luma_flag = value;

            BITS_PARSE("slice_sao_chroma_flag", value, ps_bitstrm, 1);
            ps_slice_hdr->i1_slice_sao_chroma_flag = value;

 }

        ps_slice_hdr->i1_max_num_merge_cand = 1;
        ps_slice_hdr->i1_cabac_init_flag = 0;

        ps_slice_hdr->i1_num_ref_idx_l0_active = 0;
        ps_slice_hdr->i1_num_ref_idx_l1_active = 0;
        ps_slice_hdr->i1_slice_cb_qp_offset = 0;
        ps_slice_hdr->i1_slice_cr_qp_offset = 0;
 if((PSLICE == ps_slice_hdr->i1_slice_type) ||
 (BSLICE == ps_slice_hdr->i1_slice_type))
 {
            BITS_PARSE("num_ref_idx_active_override_flag", value, ps_bitstrm, 1);
            ps_slice_hdr->i1_num_ref_idx_active_override_flag = value;

 if(ps_slice_hdr->i1_num_ref_idx_active_override_flag)
 {
                UEV_PARSE("num_ref_idx_l0_active_minus1", value, ps_bitstrm);
                ps_slice_hdr->i1_num_ref_idx_l0_active = value + 1;

 if(BSLICE == ps_slice_hdr->i1_slice_type)
 {
                    UEV_PARSE("num_ref_idx_l1_active_minus1", value, ps_bitstrm);
                    ps_slice_hdr->i1_num_ref_idx_l1_active = value + 1;
 }

 }
 else
 {
                ps_slice_hdr->i1_num_ref_idx_l0_active = ps_pps->i1_num_ref_idx_l0_default_active;

 if(BSLICE == ps_slice_hdr->i1_slice_type)
 {
                    ps_slice_hdr->i1_num_ref_idx_l1_active = ps_pps->i1_num_ref_idx_l1_default_active;
 }
 }

            ps_slice_hdr->i1_num_ref_idx_l0_active = CLIP3(ps_slice_hdr->i1_num_ref_idx_l0_active, 0, MAX_DPB_SIZE - 1);
            ps_slice_hdr->i1_num_ref_idx_l1_active = CLIP3(ps_slice_hdr->i1_num_ref_idx_l1_active, 0, MAX_DPB_SIZE - 1);

 if(0 == num_poc_total_curr)
 return IHEVCD_IGNORE_SLICE;
 if((ps_pps->i1_lists_modification_present_flag) && (num_poc_total_curr > 1))
 {
                ihevcd_ref_pic_list_modification(ps_bitstrm,
                                                 ps_slice_hdr, num_poc_total_curr);
 }
 else
 {
                ps_slice_hdr->s_rplm.i1_ref_pic_list_modification_flag_l0 = 0;
                ps_slice_hdr->s_rplm.i1_ref_pic_list_modification_flag_l1 = 0;
 }

 if(BSLICE == ps_slice_hdr->i1_slice_type)
 {
                BITS_PARSE("mvd_l1_zero_flag", value, ps_bitstrm, 1);
                ps_slice_hdr->i1_mvd_l1_zero_flag = value;
 }

            ps_slice_hdr->i1_cabac_init_flag = 0;
 if(ps_pps->i1_cabac_init_present_flag)
 {
                BITS_PARSE("cabac_init_flag", value, ps_bitstrm, 1);
                ps_slice_hdr->i1_cabac_init_flag = value;

 }
            ps_slice_hdr->i1_collocated_from_l0_flag = 1;
            ps_slice_hdr->i1_collocated_ref_idx = 0;
 if(ps_slice_hdr->i1_slice_temporal_mvp_enable_flag)
 {
 if(BSLICE == ps_slice_hdr->i1_slice_type)
 {
                    BITS_PARSE("collocated_from_l0_flag", value, ps_bitstrm, 1);
                    ps_slice_hdr->i1_collocated_from_l0_flag = value;
 }

 if((ps_slice_hdr->i1_collocated_from_l0_flag  && (ps_slice_hdr->i1_num_ref_idx_l0_active > 1)) ||
 (!ps_slice_hdr->i1_collocated_from_l0_flag  && (ps_slice_hdr->i1_num_ref_idx_l1_active > 1)))
 {
                    UEV_PARSE("collocated_ref_idx", value, ps_bitstrm);
                    ps_slice_hdr->i1_collocated_ref_idx = value;
 }

 }
            ps_slice_hdr->i1_collocated_ref_idx = CLIP3(ps_slice_hdr->i1_collocated_ref_idx, 0, MAX_DPB_SIZE - 1);

 if((ps_pps->i1_weighted_pred_flag  && (PSLICE == ps_slice_hdr->i1_slice_type)) ||
 (ps_pps->i1_weighted_bipred_flag  && (BSLICE == ps_slice_hdr->i1_slice_type)))
 {
                ihevcd_parse_pred_wt_ofst(ps_bitstrm, ps_sps, ps_pps, ps_slice_hdr);
 }
            UEV_PARSE("five_minus_max_num_merge_cand", value, ps_bitstrm);
            ps_slice_hdr->i1_max_num_merge_cand = 5 - value;

 }
        ps_slice_hdr->i1_max_num_merge_cand = CLIP3(ps_slice_hdr->i1_max_num_merge_cand, 1, 5);
        SEV_PARSE("slice_qp_delta", value, ps_bitstrm);
        ps_slice_hdr->i1_slice_qp_delta = value;

 if(ps_pps->i1_pic_slice_level_chroma_qp_offsets_present_flag)
 {
            SEV_PARSE("slice_cb_qp_offset", value, ps_bitstrm);
            ps_slice_hdr->i1_slice_cb_qp_offset = value;

            SEV_PARSE("slice_cr_qp_offset", value, ps_bitstrm);
            ps_slice_hdr->i1_slice_cr_qp_offset = value;

 }
        ps_slice_hdr->i1_deblocking_filter_override_flag = 0;
        ps_slice_hdr->i1_slice_disable_deblocking_filter_flag  = ps_pps->i1_pic_disable_deblocking_filter_flag;
        ps_slice_hdr->i1_beta_offset_div2 = ps_pps->i1_beta_offset_div2;
        ps_slice_hdr->i1_tc_offset_div2 = ps_pps->i1_tc_offset_div2;

        disable_deblocking_filter_flag = ps_pps->i1_pic_disable_deblocking_filter_flag;

 if(ps_pps->i1_deblocking_filter_control_present_flag)
 {

 if(ps_pps->i1_deblocking_filter_override_enabled_flag)
 {
                BITS_PARSE("deblocking_filter_override_flag", value, ps_bitstrm, 1);
                ps_slice_hdr->i1_deblocking_filter_override_flag = value;
 }

 if(ps_slice_hdr->i1_deblocking_filter_override_flag)
 {
                BITS_PARSE("slice_disable_deblocking_filter_flag", value, ps_bitstrm, 1);
                ps_slice_hdr->i1_slice_disable_deblocking_filter_flag = value;
                disable_deblocking_filter_flag = ps_slice_hdr->i1_slice_disable_deblocking_filter_flag;

 if(!ps_slice_hdr->i1_slice_disable_deblocking_filter_flag)
 {
                    SEV_PARSE("beta_offset_div2", value, ps_bitstrm);
                    ps_slice_hdr->i1_beta_offset_div2 = value;

                    SEV_PARSE("tc_offset_div2", value, ps_bitstrm);
                    ps_slice_hdr->i1_tc_offset_div2 = value;

 }
 }
 }

        ps_slice_hdr->i1_slice_loop_filter_across_slices_enabled_flag = ps_pps->i1_loop_filter_across_slices_enabled_flag;
 if(ps_pps->i1_loop_filter_across_slices_enabled_flag  &&
 (ps_slice_hdr->i1_slice_sao_luma_flag  ||  ps_slice_hdr->i1_slice_sao_chroma_flag  || !disable_deblocking_filter_flag))
 {
            BITS_PARSE("slice_loop_filter_across_slices_enabled_flag", value, ps_bitstrm, 1);
            ps_slice_hdr->i1_slice_loop_filter_across_slices_enabled_flag = value;
 }

 }

 /* Check sanity of slice */
 if((!first_slice_in_pic_flag) &&
 (ps_codec->i4_pic_present))
 {
 slice_header_t *ps_slice_hdr_base = ps_codec->ps_slice_hdr_base;

 /* According to the standard, the above conditions must be satisfied - But for error resilience,
         * only the following conditions are checked */
 if((ps_slice_hdr_base->i1_pps_id != ps_slice_hdr->i1_pps_id) ||
 (ps_slice_hdr_base->i4_pic_order_cnt_lsb != ps_slice_hdr->i4_pic_order_cnt_lsb))
 {
 return IHEVCD_IGNORE_SLICE;
 }

 }

 if(0 == ps_codec->i4_pic_present)
 {
        ps_slice_hdr->i4_abs_pic_order_cnt = ihevcd_calc_poc(ps_codec, ps_nal, ps_sps->i1_log2_max_pic_order_cnt_lsb, ps_slice_hdr->i4_pic_order_cnt_lsb);
 }
 else
 {
        ps_slice_hdr->i4_abs_pic_order_cnt = ps_codec->s_parse.i4_abs_pic_order_cnt;
 }

 if(!first_slice_in_pic_flag)
 {
 /* Check if the current slice belongs to the same pic (Pic being parsed) */
 if(ps_codec->s_parse.i4_abs_pic_order_cnt == ps_slice_hdr->i4_abs_pic_order_cnt)
 {

 /* If the Next CTB's index is less than the slice address,
             * the previous slice is incomplete.
             * Indicate slice error, and treat the remaining CTBs as skip */
 if(slice_address > ps_codec->s_parse.i4_next_ctb_indx)

             {
                 if(ps_codec->i4_pic_present)
                 {
                    slice_header_t *ps_slice_hdr_next;
                    ps_codec->i4_slice_error = 1;
                    ps_codec->s_parse.i4_cur_slice_idx--;
                    if(ps_codec->s_parse.i4_cur_slice_idx < 0)
                        ps_codec->s_parse.i4_cur_slice_idx = 0;
                    ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + ((ps_codec->s_parse.i4_cur_slice_idx + 1) & (MAX_SLICE_HDR_CNT - 1));
                    ps_slice_hdr_next->i2_ctb_x = slice_address % ps_sps->i2_pic_wd_in_ctb;
                    ps_slice_hdr_next->i2_ctb_y = slice_address / ps_sps->i2_pic_wd_in_ctb;
                    return ret;
                 }
                 else
                 {
 return IHEVCD_IGNORE_SLICE;
 }
 }
 /* If the slice address is less than the next CTB's index,
             * extra CTBs have been decoded in the previous slice.
             * Ignore the current slice. Treat it as incomplete */
 else if(slice_address < ps_codec->s_parse.i4_next_ctb_indx)
 {
 return IHEVCD_IGNORE_SLICE;
 }
 else
 {
                ps_codec->i4_slice_error = 0;
 }
 }

 /* The current slice does not belong to the pic that is being parsed */
 else
 {
 /* The previous pic is incomplete.
             * Treat the remaining CTBs as skip */
 if(ps_codec->i4_pic_present)
 {
 slice_header_t *ps_slice_hdr_next;
                ps_codec->i4_slice_error = 1;
                ps_codec->s_parse.i4_cur_slice_idx--;
 if(ps_codec->s_parse.i4_cur_slice_idx < 0)
                    ps_codec->s_parse.i4_cur_slice_idx = 0;

                ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + ((ps_codec->s_parse.i4_cur_slice_idx + 1) & (MAX_SLICE_HDR_CNT - 1));
                ps_slice_hdr_next->i2_ctb_x = 0;
                ps_slice_hdr_next->i2_ctb_y = ps_codec->s_parse.ps_sps->i2_pic_ht_in_ctb;
 return ret;
 }

 /* If the previous pic is complete,
             * return if the current slice is dependant
             * otherwise, update the parse context's POC */
 else
 {
 if(ps_slice_hdr->i1_dependent_slice_flag)
 return IHEVCD_IGNORE_SLICE;

                ps_codec->s_parse.i4_abs_pic_order_cnt = ps_slice_hdr->i4_abs_pic_order_cnt;
 }
 }
 }

 /* If the slice is the first slice in the pic, update the parse context's POC */
 else
 {
 /* If the first slice is repeated, ignore the second occurrence
         * If any other slice is repeated, the CTB addr will be greater than the slice addr,
         * and hence the second occurrence is ignored */
 if(ps_codec->s_parse.i4_abs_pic_order_cnt == ps_slice_hdr->i4_abs_pic_order_cnt)
 return IHEVCD_IGNORE_SLICE;

        ps_codec->s_parse.i4_abs_pic_order_cnt = ps_slice_hdr->i4_abs_pic_order_cnt;
 }

    ps_slice_hdr->i4_num_entry_point_offsets = 0;
 if((ps_pps->i1_tiles_enabled_flag) ||
 (ps_pps->i1_entropy_coding_sync_enabled_flag))
 {
        UEV_PARSE("num_entry_point_offsets", value, ps_bitstrm);
        ps_slice_hdr->i4_num_entry_point_offsets = value;

 {
            WORD32 max_num_entry_point_offsets;
 if((ps_pps->i1_tiles_enabled_flag) &&
 (ps_pps->i1_entropy_coding_sync_enabled_flag))
 {
                max_num_entry_point_offsets = ps_pps->i1_num_tile_columns * (ps_sps->i2_pic_ht_in_ctb - 1);
 }
 else if(ps_pps->i1_tiles_enabled_flag)
 {
                max_num_entry_point_offsets = ps_pps->i1_num_tile_columns * ps_pps->i1_num_tile_rows;
 }
 else
 {
                max_num_entry_point_offsets = (ps_sps->i2_pic_ht_in_ctb - 1);
 }

            ps_slice_hdr->i4_num_entry_point_offsets = CLIP3(ps_slice_hdr->i4_num_entry_point_offsets,
 0, max_num_entry_point_offsets);
 }

 if(ps_slice_hdr->i4_num_entry_point_offsets > 0)
 {
            UEV_PARSE("offset_len_minus1", value, ps_bitstrm);
            ps_slice_hdr->i1_offset_len = value + 1;

 for(i = 0; i < ps_slice_hdr->i4_num_entry_point_offsets; i++)
 {
                BITS_PARSE("entry_point_offset", value, ps_bitstrm, ps_slice_hdr->i1_offset_len);

 /* TODO: pu4_entry_point_offset needs to be initialized */
 }

 }
 }

 if(ps_pps->i1_slice_header_extension_present_flag)
 {
        UEV_PARSE("slice_header_extension_length", value, ps_bitstrm);
        ps_slice_hdr->i2_slice_header_extension_length = value;

 for(i = 0; i < ps_slice_hdr->i2_slice_header_extension_length; i++)
 {
            BITS_PARSE("slice_header_extension_data_byte", value, ps_bitstrm, 8);
 }

 }

    ihevcd_bits_flush_to_byte_boundary(ps_bitstrm);

 if((UWORD8 *)ps_bitstrm->pu4_buf > ps_bitstrm->pu1_buf_max)
 return IHEVCD_INVALID_PARAMETER;

 {
 dpb_mgr_t *ps_dpb_mgr = (dpb_mgr_t *)ps_codec->pv_dpb_mgr;
        WORD32 r_idx;

 if((NAL_IDR_W_LP == ps_slice_hdr->i1_nal_unit_type) ||
 (NAL_IDR_N_LP == ps_slice_hdr->i1_nal_unit_type) ||
 (NAL_BLA_N_LP == ps_slice_hdr->i1_nal_unit_type) ||
 (NAL_BLA_W_DLP == ps_slice_hdr->i1_nal_unit_type) ||
 (NAL_BLA_W_LP == ps_slice_hdr->i1_nal_unit_type) ||
 (0 == ps_codec->u4_pic_cnt))
 {
 for(i = 0; i < MAX_DPB_BUFS; i++)
 {
 if(ps_dpb_mgr->as_dpb_info[i].ps_pic_buf)
 {
 pic_buf_t *ps_pic_buf = ps_dpb_mgr->as_dpb_info[i].ps_pic_buf;
 mv_buf_t *ps_mv_buf;

 /* Long term index is set to MAX_DPB_BUFS to ensure it is not added as LT */
                    ihevc_dpb_mgr_del_ref((dpb_mgr_t *)ps_codec->pv_dpb_mgr, (buf_mgr_t *)ps_codec->pv_pic_buf_mgr, ps_pic_buf->i4_abs_poc);
 /* Find buffer id of the MV bank corresponding to the buffer being freed (Buffer with POC of u4_abs_poc) */
                    ps_mv_buf = (mv_buf_t *)ps_codec->ps_mv_buf;
 for(j = 0; j < ps_codec->i4_max_dpb_size; j++)
 {
 if(ps_mv_buf && ps_mv_buf->i4_abs_poc == ps_pic_buf->i4_abs_poc)
 {
                            ihevc_buf_mgr_release((buf_mgr_t *)ps_codec->pv_mv_buf_mgr, j, BUF_MGR_REF);
 break;
 }
                        ps_mv_buf++;
 }

 }

 }

 /* Initialize the reference lists to NULL
             * This is done to take care of the cases where the first pic is not IDR
             * but the reference list is not created for the first pic because
             * pic count is zero leaving the reference list uninitialised  */
 for(r_idx = 0; r_idx < MAX_DPB_SIZE; r_idx++)
 {
                ps_slice_hdr->as_ref_pic_list0[r_idx].pv_pic_buf = NULL;
                ps_slice_hdr->as_ref_pic_list0[r_idx].pv_mv_buf = NULL;

                ps_slice_hdr->as_ref_pic_list1[r_idx].pv_pic_buf = NULL;
                ps_slice_hdr->as_ref_pic_list1[r_idx].pv_mv_buf = NULL;
 }

 }
 else
 {
            ret = ihevcd_ref_list(ps_codec, ps_pps, ps_sps, ps_slice_hdr);
 if ((WORD32)IHEVCD_SUCCESS != ret)
 {
 return ret;
 }

 }

 }

 /* Fill the remaining entries of the reference lists with the nearest POC
     * This is done to handle cases where there is a corruption in the reference index */
 if(ps_codec->i4_pic_present)
 {
 pic_buf_t *ps_pic_buf_ref;
 mv_buf_t *ps_mv_buf_ref;
        WORD32 r_idx;
 dpb_mgr_t *ps_dpb_mgr = (dpb_mgr_t *)ps_codec->pv_dpb_mgr;
 buf_mgr_t *ps_mv_buf_mgr = (buf_mgr_t *)ps_codec->pv_mv_buf_mgr;

        ps_pic_buf_ref = ihevc_dpb_mgr_get_ref_by_nearest_poc(ps_dpb_mgr, ps_slice_hdr->i4_abs_pic_order_cnt);
 if(NULL == ps_pic_buf_ref)
 {
            ps_pic_buf_ref = ps_codec->as_process[0].ps_cur_pic;
            ps_mv_buf_ref = ps_codec->s_parse.ps_cur_mv_buf;
 }
 else
 {
            ps_mv_buf_ref = ihevcd_mv_mgr_get_poc(ps_mv_buf_mgr, ps_pic_buf_ref->i4_abs_poc);
 }

 for(r_idx = 0; r_idx < ps_slice_hdr->i1_num_ref_idx_l0_active; r_idx++)
 {
 if(NULL == ps_slice_hdr->as_ref_pic_list0[r_idx].pv_pic_buf)
 {
                ps_slice_hdr->as_ref_pic_list0[r_idx].pv_pic_buf = (void *)ps_pic_buf_ref;
                ps_slice_hdr->as_ref_pic_list0[r_idx].pv_mv_buf = (void *)ps_mv_buf_ref;
 }
 }

 for(r_idx = ps_slice_hdr->i1_num_ref_idx_l0_active; r_idx < MAX_DPB_SIZE; r_idx++)
 {
            ps_slice_hdr->as_ref_pic_list0[r_idx].pv_pic_buf = (void *)ps_pic_buf_ref;
            ps_slice_hdr->as_ref_pic_list0[r_idx].pv_mv_buf = (void *)ps_mv_buf_ref;
 }

 for(r_idx = 0; r_idx < ps_slice_hdr->i1_num_ref_idx_l1_active; r_idx++)
 {
 if(NULL == ps_slice_hdr->as_ref_pic_list1[r_idx].pv_pic_buf)
 {
                ps_slice_hdr->as_ref_pic_list1[r_idx].pv_pic_buf = (void *)ps_pic_buf_ref;
                ps_slice_hdr->as_ref_pic_list1[r_idx].pv_mv_buf = (void *)ps_mv_buf_ref;
 }
 }

 for(r_idx = ps_slice_hdr->i1_num_ref_idx_l1_active; r_idx < MAX_DPB_SIZE; r_idx++)
 {
            ps_slice_hdr->as_ref_pic_list1[r_idx].pv_pic_buf = (void *)ps_pic_buf_ref;
            ps_slice_hdr->as_ref_pic_list1[r_idx].pv_mv_buf = (void *)ps_mv_buf_ref;
 }
 }

 /* Update slice address in the header */
 if(!ps_slice_hdr->i1_first_slice_in_pic_flag)
 {
        ps_slice_hdr->i2_ctb_x = slice_address % ps_sps->i2_pic_wd_in_ctb;
        ps_slice_hdr->i2_ctb_y = slice_address / ps_sps->i2_pic_wd_in_ctb;

 if(!ps_slice_hdr->i1_dependent_slice_flag)
 {
            ps_slice_hdr->i2_independent_ctb_x = ps_slice_hdr->i2_ctb_x;
            ps_slice_hdr->i2_independent_ctb_y = ps_slice_hdr->i2_ctb_y;
 }
 }
 else
 {
        ps_slice_hdr->i2_ctb_x = 0;
        ps_slice_hdr->i2_ctb_y = 0;

        ps_slice_hdr->i2_independent_ctb_x = 0;
        ps_slice_hdr->i2_independent_ctb_y = 0;
 }

 /* If the first slice in the pic is missing, copy the current slice header to
     * the first slice's header */
 if((!first_slice_in_pic_flag) &&
 (0 == ps_codec->i4_pic_present))
 {

         slice_header_t *ps_slice_hdr_prev = ps_codec->s_parse.ps_slice_hdr_base;
         ihevcd_copy_slice_hdr(ps_codec, 0, (ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1)));

        ps_codec->i4_slice_error = 1;

         ps_slice_hdr_prev->i2_ctb_x = 0;
         ps_slice_hdr_prev->i2_ctb_y = 0;

        ps_codec->s_parse.i4_ctb_x = 0;
        ps_codec->s_parse.i4_ctb_y = 0;

        ps_codec->s_parse.i4_cur_slice_idx = 0;

 if((ps_slice_hdr->i2_ctb_x == 0) &&
 (ps_slice_hdr->i2_ctb_y == 0))
 {
            ps_slice_hdr->i2_ctb_x++;
 }
 }

 {
 /* If skip B is enabled,
         * ignore pictures that are non-reference
         * TODO: (i1_nal_unit_type < NAL_BLA_W_LP) && (i1_nal_unit_type % 2 == 0) only says it is
         * sub-layer non-reference slice. May need to find a way to detect actual non-reference pictures*/

 if((i1_nal_unit_type < NAL_BLA_W_LP) &&
 (i1_nal_unit_type % 2 == 0))
 {
 if(IVD_SKIP_B == ps_codec->e_pic_skip_mode)
 return IHEVCD_IGNORE_SLICE;
 }

 /* If skip PB is enabled,
         * decode only I slices */
 if((IVD_SKIP_PB == ps_codec->e_pic_skip_mode) &&
 (ISLICE != ps_slice_hdr->i1_slice_type))
 {
 return IHEVCD_IGNORE_SLICE;

         }
     }

     return ret;
 }

An information disclosure vulnerability in the Android media framework (libhevc). Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0, 8.1. Android ID: A-65034175.