Google Chrome V8 – Object Allocation Size Integer Overflow

  • 作者: Google Security Research
    日期: 2018-05-04
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/44584/
  • There's an integer overflow in computing the required allocation size when instantiating a new javascript object. 
    
    See the following code in objects.cc
    
    // static
    bool JSFunction::CalculateInstanceSizeForDerivedClass(
    Handle<JSFunction> function, InstanceType instance_type,
    int requested_embedder_fields, int* instance_size,
    int* in_object_properties) {
    Isolate* isolate = function->GetIsolate();
    int expected_nof_properties = 0;
    bool result = true;
    for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
     !iter.IsAtEnd(); iter.Advance()) {
    Handle<JSReceiver> current =
    PrototypeIterator::GetCurrent<JSReceiver>(iter);
    if (!current->IsJSFunction()) break;
    Handle<JSFunction> func(Handle<JSFunction>::cast(current));
    // The super constructor should be compiled for the number of expected
    // properties to be available.
    Handle<SharedFunctionInfo> shared(func->shared());
    if (shared->is_compiled() ||
    Compiler::Compile(func, Compiler::CLEAR_EXCEPTION)) {
    DCHECK(shared->is_compiled());
    expected_nof_properties += shared->expected_nof_properties(); // <--- overflow here!
    } else if (!shared->is_compiled()) {
    // In case there was a compilation error for the constructor we will
    // throw an error during instantiation. Hence we directly return 0;
    result = false;
    break;
    }
    if (!IsDerivedConstructor(shared->kind())) {
    break;
    }
    }
    CalculateInstanceSizeHelper(instance_type, true, requested_embedder_fields,
    expected_nof_properties, instance_size,
    in_object_properties);
    return result;
    }
    
    By supplying a long prototype chain of objects with a large expected_nof_properties we can control the resulting value of instance_size by causing (requested_embedder_fields + requested_in_object_properties) << kPointerSizeLog2 to be overflown to a small negative value, resulting in an allocation smaller than header_size, which is the minimum required size for the base object class being allocated. This results in memory corruption when the object is initialised/used.
    
    void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
     bool has_prototype_slot,
     int requested_embedder_fields,
     int requested_in_object_properties,
     int* instance_size,
     int* in_object_properties) {
    int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
    DCHECK_LE(requested_embedder_fields,
    (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2);
    *instance_size =
    Min(header_size +
    ((requested_embedder_fields + requested_in_object_properties)
     << kPointerSizeLog2),
    JSObject::kMaxInstanceSize);
    *in_object_properties = ((*instance_size - header_size) >> kPointerSizeLog2) -
    requested_embedder_fields;
    }
    
    The attached PoC crashes current stable on linux.
    
    See crash report ID: 307546648ba8a84a
    
    Chrome issue is https://bugs.chromium.org/p/chromium/issues/detail?id=808192
    
    Attaching the working exploit for this issue.
    
    Note that issue_808192.html is a template - it requires server.py to do a version check and patch a few version dependent constants in, since some object layouts have changed during the range of Chrome versions on which the exploit was tested.
    
    
    Proof of Concept:
    https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/44584.zip