Commit message: None
CVE: CVE-2018-9490
CWE: CWE-704
Vulnerability description: 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

Project: Android

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

Project: Android

   explicit ElementsAccessorBase(const char* name)

Project: Android

 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
 Handle<JSObject> receiver,
 Handle<Object> value,
 uint32_t start_from, uint32_t length) {
    DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
 bool search_for_hole = value->IsUndefined(isolate);

 if (!search_for_hole) {
 Maybe<bool> result = Nothing<bool>();
 if (DictionaryElementsAccessor::IncludesValueFastPath(
              isolate, receiver, value, start_from, length, &result)) {

         return result;
       }
     }
    Handle<Map> original_map(receiver->map(), isolate);
     Handle<SeededNumberDictionary> dictionary(
         SeededNumberDictionary::cast(receiver->elements()), isolate);
     for (uint32_t k = start_from; k < length; ++k) {
      DCHECK_EQ(receiver->map(), *original_map);
       int entry = dictionary->FindEntry(isolate, k);
       if (entry == SeededNumberDictionary::kNotFound) {
         if (search_for_hole) return Just(true);
 continue;
 }

 PropertyDetails details = GetDetailsImpl(*dictionary, entry);
 switch (details.kind()) {
 case kData: {
 Object* element_k = dictionary->ValueAt(entry);
 if (value->SameValueZero(element_k)) return Just(true);
 break;
 }
 case kAccessor: {
 LookupIterator it(isolate, receiver, k,
 LookupIterator::OWN_SKIP_INTERCEPTOR);
          DCHECK(it.IsFound());
          DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
 Handle<Object> element_k;

          ASSIGN_RETURN_ON_EXCEPTION_VALUE(
              isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
 Nothing<bool>());

 if (value->SameValueZero(*element_k)) return Just(true);

 if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
 return IncludesValueSlowPath(isolate, receiver, value, k + 1,
                                         length);
 }

 if (*dictionary == receiver->elements()) continue;

 if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
 if (receiver->map()->GetInitialElements() == receiver->elements()) {
 return Just(search_for_hole);
 }
 return IncludesValueSlowPath(isolate, receiver, value, k + 1,
                                         length);
 }
          dictionary = handle(
 SeededNumberDictionary::cast(receiver->elements()), isolate);
 break;
 }
 }
 }
 return Just(false);
 }

Project: Android

 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
 Handle<JSObject> object,

                                        Handle<Object> value,
                                        uint32_t start_from, uint32_t length) {
     DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
    Handle<Map> original_map(object->map(), isolate);
     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()),
                                      isolate);
     bool search_for_hole = value->IsUndefined(isolate);
 
     for (uint32_t k = start_from; k < length; ++k) {
      DCHECK_EQ(object->map(), *original_map);
       uint32_t entry = GetEntryForIndexImpl(isolate, *object, *parameter_map, k,
                                             ALL_PROPERTIES);
       if (entry == kMaxUInt32) {
 if (search_for_hole) return Just(true);
 continue;
 }

 Handle<Object> element_k =
 Subclass::GetImpl(isolate, *parameter_map, entry);

 if (element_k->IsAccessorPair()) {
 LookupIterator it(isolate, object, k, LookupIterator::OWN);
        DCHECK(it.IsFound());
        DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
        ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
 Object::GetPropertyWithAccessor(&it),
 Nothing<bool>());

 if (value->SameValueZero(*element_k)) return Just(true);

 if (object->map() != *original_map) {
 return IncludesValueSlowPath(isolate, object, value, k + 1, length);
 }
 } else if (value->SameValueZero(*element_k)) {
 return Just(true);
 }
 }
 return Just(false);
 }

Project: Android

 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
 Handle<JSObject> receiver,
 Handle<Object> value,

                                          uint32_t start_from, uint32_t length) {
     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
 
    Handle<Map> original_map(receiver->map(), isolate);
     Handle<SeededNumberDictionary> dictionary(
         SeededNumberDictionary::cast(receiver->elements()), isolate);
     for (uint32_t k = start_from; k < length; ++k) {
      DCHECK_EQ(receiver->map(), *original_map);
       int entry = dictionary->FindEntry(isolate, k);
       if (entry == SeededNumberDictionary::kNotFound) {
         continue;
 }

 PropertyDetails details = GetDetailsImpl(*dictionary, entry);
 switch (details.kind()) {
 case kData: {
 Object* element_k = dictionary->ValueAt(entry);
 if (value->StrictEquals(element_k)) {
 return Just<int64_t>(k);
 }
 break;
 }
 case kAccessor: {
 LookupIterator it(isolate, receiver, k,
 LookupIterator::OWN_SKIP_INTERCEPTOR);
          DCHECK(it.IsFound());
          DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
 Handle<Object> element_k;

          ASSIGN_RETURN_ON_EXCEPTION_VALUE(
              isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
 Nothing<int64_t>());

 if (value->StrictEquals(*element_k)) return Just<int64_t>(k);

 if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
 return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
                                        length);
 }

 if (*dictionary == receiver->elements()) continue;

 if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
 return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
                                        length);
 }
          dictionary = handle(
 SeededNumberDictionary::cast(receiver->elements()), isolate);
 break;
 }
 }
 }
 return Just<int64_t>(-1);
 }

Project: Android

 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
 Handle<JSObject> object,

                                          Handle<Object> value,
                                          uint32_t start_from, uint32_t length) {
     DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
    Handle<Map> original_map(object->map(), isolate);
     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()),
                                      isolate);
 
     for (uint32_t k = start_from; k < length; ++k) {
      DCHECK_EQ(object->map(), *original_map);
       uint32_t entry = GetEntryForIndexImpl(isolate, *object, *parameter_map, k,
                                             ALL_PROPERTIES);
       if (entry == kMaxUInt32) {
 continue;
 }

 Handle<Object> element_k =
 Subclass::GetImpl(isolate, *parameter_map, entry);

 if (element_k->IsAccessorPair()) {
 LookupIterator it(isolate, object, k, LookupIterator::OWN);
        DCHECK(it.IsFound());
        DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
        ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
 Object::GetPropertyWithAccessor(&it),
 Nothing<int64_t>());

 if (value->StrictEquals(*element_k)) {
 return Just<int64_t>(k);
 }

 if (object->map() != *original_map) {
 return IndexOfValueSlowPath(isolate, object, value, k + 1, length);
 }
 } else if (value->StrictEquals(*element_k)) {
 return Just<int64_t>(k);
 }
 }
 return Just<int64_t>(-1);
 }